package com.wstuo.itsm.request.service;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
import org.apache.struts2.json.JSONException;
import org.apache.struts2.json.JSONUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.wstuo.common.Luence.LuenceUtil;
import com.wstuo.common.bpm.api.IBPI;
import com.wstuo.common.bpm.api.ICustomAssign;
import com.wstuo.common.bpm.dto.FlowActivityDTO;
import com.wstuo.common.bpm.dto.ProcessAssignDTO;
import com.wstuo.common.bpm.dto.ProcessHandleDTO;
import com.wstuo.common.bpm.dto.ProcessHistoriesDTO;
import com.wstuo.common.bpm.service.IFlowPropertyService;
import com.wstuo.common.config.attachment.entity.Attachment;
import com.wstuo.common.config.attachment.service.IAttachmentService;
import com.wstuo.common.config.basicConfig.service.ICurrencyService;
import com.wstuo.common.config.category.dao.IEventCategoryDAO;
import com.wstuo.common.config.category.dto.EventCategoryDTO;
import com.wstuo.common.config.category.entity.EventCategory;
import com.wstuo.common.config.category.service.IEventCategoryService;
import com.wstuo.common.config.comment.dao.ICommentDAO;
import com.wstuo.common.config.comment.entity.Comment;
import com.wstuo.common.config.customfilter.dto.KeyTransferDTO;
import com.wstuo.common.config.customfilter.service.IFilterService;
import com.wstuo.common.config.customfilter.service.ILinksEventQueryServices;
import com.wstuo.common.config.dictionary.dao.IDataDictionaryItemsDAO;
import com.wstuo.common.config.dictionary.entity.DataDictionaryItems;
import com.wstuo.common.config.historyData.dto.HistoryDataDTO;
import com.wstuo.common.config.historyData.service.IHistoryDataService;
import com.wstuo.common.config.moduleManage.dao.IModuleManageDAO;
import com.wstuo.common.config.moduleManage.entity.ModuleManage;
import com.wstuo.common.customForm.dao.IFieldDAO;
import com.wstuo.common.customForm.entity.Field;
import com.wstuo.common.exportmq.ExportMessageProducer;
import com.wstuo.common.noticeRule.dto.NoticeInfoDTO;
import com.wstuo.common.noticeRule.service.INoticeRuleService;
import com.wstuo.common.priorityMatrix.dao.IPriorityMatrixStatusDAO;
import com.wstuo.common.priorityMatrix.entity.PriorityMatrixStatus;
import com.wstuo.common.rules.DroolsFacade;
import com.wstuo.common.rules.drool.RulePathFile;
import com.wstuo.common.rules.drool.RulePathType;
import com.wstuo.common.rules.entity.RulePackage;
import com.wstuo.common.sla.dao.ISLAContractDAO;
import com.wstuo.common.sla.dao.ISLARuleDAO;
import com.wstuo.common.sla.dto.SLARuleQueryDTO;
import com.wstuo.common.sla.entity.SLAContract;
import com.wstuo.common.sla.entity.SLARule;
import com.wstuo.common.tools.dao.IEmailDAO;
import com.wstuo.common.tools.dao.IUserReturnVisitDAO;
import com.wstuo.common.tools.dto.AutomaticallyAssignedDTO;
import com.wstuo.common.tools.dto.CostDTO;
import com.wstuo.common.tools.dto.ExportPageDTO;
import com.wstuo.common.tools.dto.ExportQueryDTO;
import com.wstuo.common.tools.dto.HistoryRecordDTO;
import com.wstuo.common.tools.dto.StatResultDTO;
import com.wstuo.common.tools.dto.TaskDTO;
import com.wstuo.common.tools.entity.EmailMessage;
import com.wstuo.common.tools.entity.ExportInfo;
import com.wstuo.common.tools.service.ICostService;
import com.wstuo.common.tools.service.IEventAttachmentService;
import com.wstuo.common.tools.service.IExportInfoService;
import com.wstuo.common.tools.service.IHistoryRecordService;
import com.wstuo.common.tools.service.ITaskService;
import com.wstuo.itsm.cim.dao.ICIDAO;
import com.wstuo.itsm.cim.dto.CIGridDTO;
import com.wstuo.itsm.cim.entity.CI;
import com.wstuo.itsm.domain.util.ModuleUtils;
import com.wstuo.itsm.itsop.itsopuser.dto.CustomerDataCountDTO;
import com.wstuo.itsm.itsop.itsopuser.service.IITSOPUserService;
import com.wstuo.itsm.knowledge.dao.IKnowledgeDAO;
import com.wstuo.itsm.knowledge.entity.KnowledgeInfo;
import com.wstuo.itsm.request.dao.IRequestDAO;
import com.wstuo.itsm.request.dto.CommentDTO;
import com.wstuo.itsm.request.dto.RequestCountResultDTO;
import com.wstuo.itsm.request.dto.RequestDTO;
import com.wstuo.itsm.request.dto.RequestDetailDTO;
import com.wstuo.itsm.request.dto.RequestGridDTO;
import com.wstuo.itsm.request.dto.RequestHttpDTO;
import com.wstuo.itsm.request.dto.RequestQueryDTO;
import com.wstuo.itsm.request.entity.EventCount;
import com.wstuo.itsm.request.entity.Request;
import com.wstuo.itsm.request.utils.CalcPredictTimeUtils;
import com.wstuo.itsm.state.utils.SLAState;
import com.wstuo.common.dto.PageDTO;
import com.wstuo.common.exception.ApplicationException;
import com.wstuo.common.file.csv.CSVReader;
import com.wstuo.common.file.csv.CSVWriter;
import com.wstuo.common.jbpm.dao.IJbpmTaskDAO;
import com.wstuo.common.proxy.service.IProxyService;
import com.wstuo.common.security.dao.HolidayDAO;
import com.wstuo.common.security.dao.IOrganizationDAO;
import com.wstuo.common.security.dao.IOrganizationServicesDAO;
import com.wstuo.common.security.dao.IUserDAO;
import com.wstuo.common.security.dao.ServiceTimeDAO;
import com.wstuo.common.security.dto.UserQueryDTO;
import com.wstuo.common.security.dto.WorkingTimeDTO;
import com.wstuo.common.security.entity.Holiday;
import com.wstuo.common.security.entity.Organization;
import com.wstuo.common.security.entity.OrganizationServices;
import com.wstuo.common.security.entity.Role;
import com.wstuo.common.security.entity.ServiceTime;
import com.wstuo.common.security.entity.User;
import com.wstuo.common.security.service.IOrganizationService;
import com.wstuo.common.security.service.IUserInfoService;
import com.wstuo.common.security.utils.AppConfigUtils;
import com.wstuo.common.security.utils.AppContext;
import com.wstuo.common.security.utils.FileEncodeUtils;
import com.wstuo.common.security.utils.HtmlSpirit;
import com.wstuo.common.security.utils.LanguageContent;
import com.wstuo.common.util.StringUtils;
import com.wstuo.common.util.TimeUtils;

/**
 * 请求服务层
 * 
 * @author Qiu
 * 
 * 
 * 
 */
public class RequestService implements IRequestService{
	final static Logger LOGGER = Logger.getLogger(RequestService.class);
	 

	// 规则
	private DroolsFacade droolsFacade = new DroolsFacade();
	private CalcPredictTimeUtils calcPredictTimeUtils = new CalcPredictTimeUtils();
	@Autowired
	private IBPI bpi;
	@Autowired
	private IRequestDAO requestDAO;
	@Autowired
	private IOrganizationDAO organizationDAO;
	@Autowired
	private IUserDAO userDAO;
	@Autowired
	private IDataDictionaryItemsDAO dataDictionaryItemsDAO;
	@Autowired
	private ISLAContractDAO slaContractDAO;
	@Autowired
	private IOrganizationServicesDAO organizationServicesDAO;
	@Autowired
	private HolidayDAO holidayDAO;
	@Autowired
	private ServiceTimeDAO serviceTimeDAO;
	@Autowired
	private INoticeRuleService noticeRuleService;
	@Autowired
	private ISLARuleDAO slaRuleDAO;
	@Autowired
	private ICIDAO ciDAO;
	@Autowired
	private IHistoryRecordService historyRecordService;
	@Autowired
	private IRequestActionService requestActionService;
	@Autowired
	private IEmailDAO emailDAO;
	@Autowired
	private IEventAttachmentService eventAttachmentService;
	@Autowired
	private IEventCategoryDAO eventCategoryDAO;
	@Autowired
	private IITSOPUserService itsopUserService;
	@Autowired
	private IHistoryDataService historyDataService;
	@Autowired
	private IFilterService filterService;
	@Autowired
	private IUserInfoService userInfoService;
	@Autowired
	private ICostService costService;
	@Autowired
	private IEventCountService eventCountService;
	@Autowired
	private IExportInfoService exportInfoService;
	@Autowired
	private ExportMessageProducer exportMessageProducer;
	private Long workTime = 0L;
	private Double cost = 0d;
	@Autowired
	private IFlowPropertyService flowPropertyService;
	@Autowired
	private IPriorityMatrixStatusDAO priorityMatrixStatusDAO;
	@Autowired
	private ICommentDAO commentDAO;
	@Autowired
	private IAttachmentService attachmentService;
	//@Autowired
	//private ICurrencyService currencyService;
	@Autowired
	private IOrganizationService organizationService;
	@Autowired
	private IProxyService proxyService;
	@Autowired
	private IJbpmTaskDAO jbpmTaskDAO;
	@Autowired
	private IUserReturnVisitDAO userReturnVisitDAO;
	@Autowired
	private IOrganizationDAO orgDAO;
	@Autowired
	private AppContext appctx;
	@Autowired
	private ILinksEventQueryServices linksEventQueryServices;
	@Autowired
	private IEventCategoryService eventCategoryService;
	@Autowired
	private ITaskService taskService;
	@Autowired
	private IKnowledgeDAO knowledgeDAO;
	@Autowired
	private IFieldDAO fieldDAO;
	@Autowired
	private IModuleManageDAO moduleManageDAO;
	/**
	 * 请求分页查询
	 * @param qdto
	 * @param sidx
	 * @param sord
	 * @return PageDTO
	 */
	@SuppressWarnings("unchecked")
	@Transactional
	public PageDTO findRequestByPage(RequestQueryDTO qdto, String sidx, String sord) {
		qdto=structureQueryDTO(qdto);//RequestQueryDTO构造
		PageDTO p = requestDAO.findPager(qdto, sidx, sord);
		List<Request> entities = p.getData();
		List<RequestGridDTO> dtos = new ArrayList<RequestGridDTO>();
		for (Request req : entities) {
			RequestGridDTO dto = new RequestGridDTO();
			entity2GridDto(req, dto);
			dtos.add(dto);
		}
		p.setData(dtos);
		return p;
	}
	
	/**
	 * 查询条件构造
	 * @param qdto
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@Transactional
	private RequestQueryDTO structureQueryDTO(RequestQueryDTO qdto){
		String loginName = appctx.getCurrentLoginName();
		
		if(!StringUtils.hasText(loginName) && StringUtils.hasText(qdto.getCurrentUser())){
			loginName = qdto.getCurrentUser();
		}
		if(!StringUtils.hasText(loginName) && StringUtils.hasText(qdto.getLoginName())){
			loginName = qdto.getLoginName();
		}
		
		if (qdto.getEcategoryNo() != null && qdto.getEcategoryNo() != 0){
			Long[] allSubCategoryIds = eventCategoryService.findSubCategoryIdsByEventId(qdto.getEcategoryNo());
			Long[] ableCategoryIds = userInfoService.findCategoryNosByLoginName(loginName, "Request_Category_");
			if(ableCategoryIds!=null){
				List<Long> categoryIds = (List<Long>) CollectionUtils.intersection(Arrays.asList(allSubCategoryIds), Arrays.asList(ableCategoryIds));
				//根据ID查看所有子节点
				qdto.setCategoryNos(categoryIds.toArray(new Long[categoryIds.size()]));
			}else{
				//根据ID查看所有子节点
				qdto.setCategoryNos(null);
			}
		}else{
			//设置查看权限(分类权限)
			qdto.setCategoryNos(userInfoService.findCategoryNosByLoginName(loginName, "Request_Category_"));
		}
			
		
		//查询负责的公司
		if(qdto.getCompanyNos()==null){
			qdto.setCompanyNos(itsopUserService.findMyAllCustomer(loginName));
		}
		//查询所属技术组
		qdto.setGroups(userInfoService.findMyRelatedTechnologyGroup(loginName));
		qdto.setOrgNo(userInfoService.findUserByName(loginName).getOrgNo());
		return qdto;
	}

	/**
	 * 自定义分页查询请求列表.(过滤器)
	 * @param qdto
	 * @return PageDTO
	 */
	@SuppressWarnings("unchecked")
	@Transactional
	public PageDTO findRequestPagerByCustomFilter(RequestQueryDTO qdto, String sidx, String sord) {
		String loginName=appctx.getCurrentLoginName();
		Long[] companyNos =null;
		Long[] categorys =null;
		if(StringUtils.hasLength(loginName)){
			// 负责的所属客户
			companyNos = itsopUserService.findMyAllCustomer(loginName);
			categorys = userInfoService.findCategoryNosByLoginName(loginName, "Request_Category_");// 设置查看权限
		}
		PageDTO pageDTO = filterService.findPageByFilter(qdto.getFilterId(), companyNos,categorys, qdto.getStart(), qdto.getLimit(), sidx, sord);
		List<Request> entities = pageDTO.getData();
		List<RequestGridDTO> dtos = new ArrayList<RequestGridDTO>();
		for (Request req : entities) {
			RequestGridDTO dto = new RequestGridDTO();
			entity2GridDto(req, dto);
			dtos.add(dto);
		}
		pageDTO.setData(dtos);
		return pageDTO;

	}

	/**
	 * 分页查询entity to dto
	 * @param req
	 * @param dto
	 */
	@Transactional
	private void entity2GridDto(Request req, RequestGridDTO dto) {
		RequestGridDTO.entity2dto(req, dto);
		if (req != null) {
			dto.setAttrVals(requestDAO.findByCustom(req.getEno(),null));
			if (req.getPid() != null) {
				dto.setPid(req.getPid());
			}
			User createdUser = req.getCreatedBy();
			if (createdUser != null) {
				dto.setCreatedByName(createdUser.getFullName());
				if (createdUser.getOrgnization() != null)
					dto.setRequesterGroup(createdUser.getOrgnization().getOrgName());
			}
			if (req.getAssigneeGroup() != null) {
				dto.setAssigneeGroupName(req.getAssigneeGroup().getOrgName());
				dto.setAssigneeGroupNo(req.getAssigneeGroup().getOrgNo());
			}
			User technician = req.getTechnician();
			if(technician!= null){
				dto.setTechnicianNo(technician.getUserId());
				dto.setTechnicianName(technician.getFullName());
			}
			if (req.getPriority() != null) {
				dto.setPriorityName(req.getPriority().getDname());
				dto.setPriorityColor(req.getPriority().getColor());
			}
			if (req.getImode() != null) {// 模式
				dto.setMode(req.getImode().getDname());
				dto.setModeColor(req.getImode().getColor());
			}
			if (req.getEffectRange() != null) {// 影响范围
				dto.setEffectRangeName(req.getEffectRange().getDname());
				dto.setEffectRangeColor(req.getEffectRange().getColor());
			}
			if (req.getSeriousness() != null) {// 紧急度
				dto.setSeriousnessName(req.getSeriousness().getDname());
				dto.setSeriousnessColor(req.getSeriousness().getColor());
			}
			if (req.getLevel() != null) {// 级别
				dto.setLevelName(req.getLevel().getDname());
				dto.setLevelColor(req.getLevel().getColor());
			}
			if (req.getOwner() != null) {
				String ownerName = req.getOwner().getLastName() + req.getOwner().getFirstName();
				dto.setOwnerName(ownerName);
				dto.setOwnerNo(req.getOwner().getUserId());
			}
			if (req.getStatus() != null) {
				dto.setStatusName(req.getStatus().getDname());
				dto.setStatusDno(req.getStatus().getDno());
				dto.setStatusColor(req.getStatus().getColor());

			}
			if (req.getRequestCategory() != null) {//
				dto.setRequestCategoryName(req.getRequestCategory().getEventName());
			}
			if (req.getEventCategory() != null) {// 请求、问题、变更统一使用
				dto.setRequestCategoryName(req.getEventCategory().getEventName());
			}
			if (req.getRequestServiceDirectory() != null) {// 请求、问题、变更统一使用
				dto.setRequestServiceDirName(req.getRequestServiceDirectory().getEventName());
			}
			// 服务目录集合
			if (req.getServiceDirectory() != null && req.getServiceDirectory().size() != 0) {
				StringBuffer strBu = new StringBuffer();
				for (EventCategory entity : req.getServiceDirectory()) {
					strBu.append(entity.getEventName() + ",");
				}
				String strName = strBu.toString();
				dto.setRequestServiceDirName(strName.substring(0, strName.length() - 1));
			}
			// 最大响应时间、最大完成时间
			if (req.getMaxResponseTime() != null) {
				dto.setMaxResponsesTime(TimeUtils.formatLongTimeToDate(req.getMaxResponseTime()));
			}
			if (req.getMaxCompleteTime() != null) {
				dto.setMaxCompletesTime(TimeUtils.formatLongTimeToDate(req.getMaxCompleteTime()));
			}
			// 所属客户
			if (req.getCompanyNo() != null && req.getCompanyNo() > 0) {
				Organization org = organizationDAO.findById(req.getCompanyNo());
				if (org != null) {
					dto.setCompanyName(org.getOrgName());
					dto.setCompanyNo(org.getOrgNo());
				}
			}
			// SLA状态
			if (req.getSlaState() != null) {
				dto.setSlaState(req.getSlaState().getDname());
				dto.setSlaStateColor(req.getSlaState().getColor());
				dto.setSlaStateDno(req.getSlaState().getDno());
			}
		}
	}

	/**
	 * 请求详细信息
	 * @param id
	 * @return RequestDetailDTO
	 */
	@Transactional
	public RequestDetailDTO findRequestById(Long id) {
		RequestDetailDTO dto = new RequestDetailDTO();
		Request req = new Request();
		req = requestDAO.findById(id);
		if (req != null) {
			entity2DetailDto(req, dto);
		}
		dto.setAttrVals(requestDAO.findByCustom(id,null));
		return dto;
	}

	/**
	 * 请求详细entity to dto
	 * @param req
	 * @param dto
	 */
	@Transactional
	private void entity2DetailDto(Request req, RequestDetailDTO dto) {
		RequestDetailDTO.entity2dto(req, dto);
		if (req.getCreatedBy() != null) {
			dto.setFullName(req.getCreatedBy().getFullName());
		}
		if (req.getSolutions() != null) {
			dto.setSolutions(req.getSolutions());
		}
		if (req.getStatus() != null) {
			dto.setStatusNo(req.getStatus().getDcode());
			dto.setStatusName(req.getStatus().getDname());
			dto.setStatusCode(req.getStatus().getDno());
			
		}
		if (req.getEffectRange() != null) {
			dto.setEffectRangeNo(req.getEffectRange().getDcode());
			dto.setEffectRangeName(req.getEffectRange().getDname());
		}
		if (req.getSeriousness() != null) {
			dto.setSeriousnessNo(req.getSeriousness().getDcode());
			dto.setSeriousnessName(req.getSeriousness().getDname());
		}
		if (req.getPriority() != null) {
			dto.setPriorityNo(req.getPriority().getDcode());
			dto.setPriorityName(req.getPriority().getDname());
		}
		if (req.getImode() != null) {
			dto.setImodeNo(req.getImode().getDcode());
			dto.setImodeName(req.getImode().getDname());
		}
		if (req.getLevel() != null) {
			dto.setLevelNo(req.getLevel().getDcode());
			dto.setLevelName(req.getLevel().getDname());
		}
		if (req.getOffmode() != null) {
			dto.setOffmodeNo(req.getOffmode().getDcode());
			dto.setOffmodeName(req.getOffmode().getDname());
		}
		User user = req.getCreatedBy();
		if (user != null) {
			dto.setCreatedByName(user.getFullName());
			dto.setCreatedByNo(user.getUserId());
			String phone = user.getPhone();
			dto.setCreatedByLoginName(user.getLoginName());
			if(StringUtils.hasText(phone)){
				dto.setCreatedByPhone(phone.trim());
			}
			String moblie = user.getMoblie();
			if(StringUtils.hasText(moblie)){
				dto.setCreateByMoblie(moblie.trim());
			}
			if(StringUtils.hasText(user.getEmail())){
				dto.setCreatedByEmail(user.getEmail().trim());
			}
			if(StringUtils.hasText(user.getOfficeAddress())){
				dto.setCreatedByOfficeAddress(user.getOfficeAddress());
			}
			if(StringUtils.hasText(user.getPosition())){
				dto.setCreateByPosition(user.getPosition().trim());
			}
			
			Organization reorg = user.getOrgnization();
			if (reorg != null) {
				dto.setCreatedByOrgName(reorg.getOrgName());
				dto.setCreatedByOrgPhone(reorg.getOfficePhone());
			}
		}
		if (req.getAssigneeGroup() != null) {
			dto.setAssigneeGroupNo(req.getAssigneeGroup().getOrgNo());
			dto.setAssigneeGroupName(req.getAssigneeGroup().getOrgName());
		}
		User technician = req.getTechnician();
		if (technician != null) {
			dto.setAssigneeNo(technician.getUserId());
			dto.setAssigneeName(technician.getFullName());
			dto.setAssigneeLoginName(technician.getLoginName());
			String currentLoginName = appctx.getCurrentLoginName();
			if (currentLoginName != null && !(technician.getLoginName().equals(currentLoginName))) {
				dto.setAgentActionShow(proxyService.findProxyOrlogin(currentLoginName, technician.getLoginName()));
			}
		}
		if (req.getTechnicalGroup() != null) {
			dto.setAssginTechnicalGroupId(req.getTechnicalGroup().getTechnicalGroupId());
			dto.setAssginTechnicalGroupName(req.getTechnicalGroup().getTechnicalGroupName());
		}
		if (req.getRelatedConfigureItems() != null) {
			List<CIGridDTO> relatedCIS = new ArrayList<CIGridDTO>();
			for (CI ci : req.getRelatedConfigureItems()) {
				CIGridDTO cidto = new CIGridDTO();
				cidto.setCiId(ci.getCiId());
				cidto.setCino(ci.getCino());
				cidto.setCiname(ci.getCiname());
				if (ci.getCategory() != null) {
					cidto.setCategoryName(ci.getCategory().getCname());
				}
				if (ci.getStatus() != null) {
					cidto.setStatus(ci.getStatus().getDname());
				}
				relatedCIS.add(cidto);
			}
			dto.setCigDTO(relatedCIS);

		}
		// 请求分类
		EventCategory ec = req.getRequestCategory();
		if (ec != null) {
			dto.setRequestCategoryNo(ec.getEventId());
			StringBuffer str = new StringBuffer();
			str.append(ec.getEventName() + "/");
			str = categoryParentEvent(ec, str);
			dto.setRequestCategoryName(str.toString().substring(0, str.toString().length() - 1));
			dto.setCategoryEavId(ec.getEavId());
		}
		// 服务目录集合
		if (req.getServiceDirectory() != null && req.getServiceDirectory().size() != 0) {
			List<EventCategory> evelist = new ArrayList<EventCategory>();
			StringBuffer str = new StringBuffer();
			for (EventCategory entity : req.getServiceDirectory()) {
				EventCategory evedto = new EventCategory();
				evedto.setEventId(entity.getEventId());
				evedto.setEventName(entity.getEventName());
				evedto.setScores(entity.getScores());
				evelist.add(evedto);
				dto.setServiceDirectory(evelist);
				str.append(entity.getEventName() + ",");
			}
			dto.setRequestServiceDirName(str.toString().substring(0, str.toString().length() - 1));
		} else {
			dto.setServiceDirectory(null);
		}
		// 最大响应时间、最大完成时间
		if (req.getMaxResponseTime() != null) {
			dto.setMaxResponsesTime(TimeUtils.formatLongTimeToDate(req.getMaxResponseTime()));
		}
		if (req.getMaxCompleteTime() != null) {
			dto.setMaxCompletesTime(TimeUtils.formatLongTimeToDate(req.getMaxCompleteTime()));
		}
		if (req.getOwner() != null) {
			dto.setOwnerName(req.getOwner().getFullName());
		}
		// 所属客户
		if (req.getCompanyNo() != null && req.getCompanyNo() > 0) {
			Organization org = organizationDAO.findById(req.getCompanyNo());
			if (org != null) {
				dto.setCompanyName(org.getOrgName());
				dto.setCompanyNo(org.getOrgNo());
			}
		}
		// SLA状态
		if (req.getSlaState() != null) {
			dto.setSlaState(req.getSlaState().getDname());
		}

		SLARule slaRule = req.getSlaRule();
		if (slaRule != null) {
			StringBuffer sb = new StringBuffer();
			sb.append(slaRule.getRuleName());
			SLAContract slaContract = slaRule.getSlaContract();
			if (slaContract != null) {
				sb.append("(" + slaRule.getSlaContract().getContractName() + ")");
			}
			dto.setSlaLevelName(sb.toString());
			dto.setSlaRuleNo(slaRule.getRuleNo());
		}
		//地点
		if(req.getLocation()!=null){
			dto.setLocationNos(req.getLocation().getEventId());
			EventCategoryDTO categoryDTO=eventCategoryService.findLocationNameById(dto.getLocationNos());
			dto.setLocationName(categoryDTO.getCategoryLocation());
		}
	}

	/**
	 * 循环查找父节点
	 * */
	private StringBuffer categoryParentEvent(EventCategory ec, StringBuffer str) {
		if (ec.getParentEvent() != null) {
			EventCategory listCategory = eventCategoryDAO.findById(ec.getParentEvent().getEventId());
			if (listCategory != null && !MODULECATEGORY.equals(listCategory.getCategoryRoot())) {
				str.append(listCategory.getEventName() + "/");
				if (listCategory.getParentEvent() != null) {
					categoryParentEvent(listCategory, str);
				}
			}
		}
		return str;
	}

	/**
	 * 提交Ticket(用于第三方集成 或单独开放给终端用户的提交事件方法)
	 * @param dto
	 * @throws NullPointerException
	 */
	@Transactional
	public Long saveTicket(RequestDTO dto) throws NullPointerException {
		Long eno = null;
		try {
			// 根据姓名查找
			User users = userDAO.findUniqueBy("loginName",dto.getLoginUserName());
			if (users == null) {
				users = userDAO.findUniqueBy("loginName", appctx.getCurrentLoginName());
			}
//			users.setMoblie(dto.getMoblie());
//			users.setPhone(dto.getPhone());
//			users.setEmail(dto.getEmail());
//			users.setOfficeAddress(dto.getOfficeAddress());
//			users.setFullName(dto.getCreator());
//			userDAO.update(users);
			dto.setCreatedByName(users.getLoginName());
			dto.setEtitle(dto.getEtitle());
			dto.setEdesc(dto.getEdesc());
			LanguageContent lc = LanguageContent.getInstance();
			dto.setActionName(lc.getContent("common.add"));

			eno = saveRequest(dto);
		} catch (Exception e) {
			LOGGER.error(e);
		}
		return eno;
	}
	
	//组装匹配规则的RequestDTO
	@Transactional
	private RequestDTO setRequestDTOToRuleMatch(RequestDTO dto){
		dto.setWeekNo(TimeUtils.getWeekOfDate(new Date()));
		User users = new User(); 
		if (dto.getCreatedByNo() != null && dto.getCreatedByNo()>0) {
			users = userDAO.findById(dto.getCreatedByNo());
		}
		if (users.getUserId() == null && dto.getCreatedByName() != null) {
			users = userDAO.findUniqueBy("loginName", dto.getCreatedByName());
		}
		if (users != null) {
			dto.setCompanyNo(users.getCompanyNo());
			dto.setCreatedByNo(users.getUserId());
			Organization org = users.getOrgnization();
			if (org != null) {
				dto.setOrganizationNo(org.getOrgNo());
				dto.setOrganizationNos(organizationService.reverFindOrg(new Long[] { org.getOrgNo() }));
			}
		}
		//请求人所属技术组
		if (users != null) {
			Set<Organization> group=users.getBelongsGroup();
			Long[] groupNos = null ;
	    	if(group!=null && group.size()>0){
	    		int i = 0;
	    		groupNos = new Long[group.size()];
	    		for (Organization org : group) {
	    			groupNos[i] = org.getOrgNo();
	    			i++;
				}
	    	}
			dto.setTechnologyGroup(groupNos);
		}
		//配置項分類規則匹配
		if (dto.getRelatedConfigureItemNos() != null) {
			Set<Long>  cicategoryNos = new HashSet<Long>();
			for (Long cid : dto.getRelatedConfigureItemNos()) {
				CI ci = ciDAO.findById(cid);
				cicategoryNos.add(ci.getCategory().getCno());
			}
			dto.setCicategoryNos((Long[]) cicategoryNos.toArray(new Long[cicategoryNos.size()]));
		}
		return dto;
	}
	
	//根据规则动作集修改请求参数
	@Transactional
	private Request setRequestByRule(RequestDTO dto,Request request){
		//繁忙程度规则匹配技术员
		if(dto.getAutomaticallyAssigned()){
			String tgId ="";
			if(request.getAssigneeGroup()!=null){
				tgId = request.getAssigneeGroup().getOrgNo().toString();
			}
			User assignee = null;
			if (dto != null && dto.getAttendance()) {//是否有排班规则
				TaskDTO taskDto = new TaskDTO();
				taskDto.setStartTime( request.getCreatedOn() );
				taskDto.setEndTime( new Date(request.getMaxResponseTime()) );
				List<String> loginNames = taskService.attendanceTaskByTimeRange(taskDto);
				assignee = automaticallyAssignedByBusy(dto.getRequestCategoryNo(),tgId,loginNames);
			}else{
				assignee = automaticallyAssignedByBusy(dto.getRequestCategoryNo(),tgId,null);
			}
			request.setTechnician(assignee);
		}
		
		//变量指派
		if(StringUtils.hasText(dto.getVariablesAssigneeType())){
			Long technicianNo = null ;
			if(request.getTechnician()!=null){
				technicianNo = request.getTechnician().getUserId();
			}
			Long groupNo = null ;
			if(request.getAssigneeGroup()!=null){
				groupNo = request.getAssigneeGroup().getOrgNo();
			}
			Long createdByNo = null ;
			if(request.getCreatedBy()!=null){
				createdByNo = request.getCreatedBy().getUserId();
			}
			User assignee =  userInfoService.setVariablesAssignee(request.getTechnician(), dto.getVariablesAssigneeType(), createdByNo,technicianNo,groupNo);
			request.setTechnician(assignee);
		}
		return request;
	}
	
	//请求升级给负责人
	@Transactional
	private Request saveRequestOwner(RequestDTO dto,Request request){
		if (dto.getUpdateLevelNo() != 0) {// 升级给负责人
			User ul = userDAO.findById(dto.getUpdateLevelNo());
			if (ul != null) {
				request.setOwner(ul);
				request.setUpgradeApplySign(2l);
			}
		}
		return request;
	}
	
	//保存扩展属性
	@Transactional
	private void saveAttr(RequestDTO dto,Request request){
		if (dto.getAttrVals() != null && dto.getAttrVals().size()>0) {
			StringBuffer sql=new StringBuffer("update cu_request set ");
			 for (Map.Entry<String, String> entry : dto.getAttrVals().entrySet()) {
				 //System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
				 sql.append(entry.getKey()+"= '" + entry.getValue()+"',");
			 }
			 sql.append("where eno=" + request.getEno());
			 requestDAO.insertAttr(sql.toString().replace(",where", " where"));
		}
	}
	
	//添加邮件转请求标识
	@Transactional
	private void addMailToRequestMark (RequestDTO dto,Request request){
		if (dto.getEmailMessage() != null) {// 邮件转请求标识
			EmailMessage emailMessage = emailDAO.findById(dto.getEmailMessage());
			if (emailMessage != null) {
				emailMessage.setIsToRequest(true);
				emailMessage.setKeyword(request.getRequestCode());
				emailMessage.setModuleCode(request.getRequestCode());
				emailDAO.merge(emailMessage);
			}
		}
	}

	/**
	 * 保存请求
	 * @param dto
	 * @return Long
	 */
	@Transactional
	public Long saveRequest(RequestDTO dto){
		//组装匹配规则的RequestDTO
		dto = setRequestDTOToRuleMatch(dto);
		Request request = new Request();
		if(!StringUtils.hasText(dto.getProcessKey())) {
			ModuleManage m=moduleManageDAO.findUniqueBy("moduleName", "request");
			request.setProcessKey(m.getPid());//bpi.getProcessDefinitionId(,  ModuleUtils.ITSM_REQUEST)
		}
		dto.setProcessKey(request.getProcessKey());
		// 请求规则匹配
		requestRuleMatch(dto);
		// 获取SLA
		dto = getRequestFitSlaRule(dto);
		// 计算SLA响应完成时间
		calcRequestSLATime(dto);
		request = saveRequestOwner(dto, request);
		this.dto2entity(dto, request);
		//SLA时间
		request = setSla(dto, request);
		// 请求创建人为空验证
		if (request.getCreatedBy() == null) {
			throw new ApplicationException("ERROR_CREATE_BY_NULL", "ERROR_REQUEST_CREATOR_IS_NULL");
		}
		request.setSlaState(dataDictionaryItemsDAO.findUniqueBy("dno",SLAState.The_Response.getValue()));// SLA状态
		// 保存请求
		List<EventCategory> eventList = new ArrayList<EventCategory>();
		if (dto.getServiceDirIds() != null && dto.getServiceDirIds().length > 0) {
			for (int i = 0; i < dto.getServiceDirIds().length; i++) {
				Long dirId = dto.getServiceDirIds()[i];
				if(dirId!=null && dirId!=0){
					EventCategory event = eventCategoryDAO.findById(dirId);
					eventList.add(event);
				}
			}
		}
		request.setServiceDirectory(eventList);
		
		request.setStatus(dataDictionaryItemsDAO.findUniqueBy("dno",REQUEST_NEW));
		requestDAO.save(request);
		//设置编号
		String eventCode = eventCountService.generateEventCode(ModuleUtils.ITSM_REQUEST,request.getEventCategory());
		request.setRequestCode(eventCode);
		request.setEventCode(eventCode);
		//根据规则动作集修改请求参数
		request = setRequestByRule(dto, request);
		if (dto.getApprovalName() != null && dto.getApprovalName() != "null") {
			List<String> longNames = new ArrayList<String>();
			// 审批人员
			request.setApprovalName(dto.getApprovalName());
			longNames.add(dto.getApprovalName());
			requestProcessNotice("", request, longNames, null, null, dto.getCurrentUser(), null, null);
		}
		// 扩展属性
		saveAttr(dto, request);
		// 附件
		if (dto.getAttachmentStr() != null && dto.getAttachmentStr() != "null" && !dto.getAttachmentStr().equals("null") || dto.getAids() != null) {
			eventAttachmentService.saveEventAttachment(dto.getCreator(), dto.getAids(), dto.getAttachmentStr(), request.getEno(), ModuleUtils.ITSM_REQUEST);
		}
		//添加邮件转请求标识
		addMailToRequestMark(dto, request);
		// 通知用户
		addRequestNotice(request, dto);
		// 保存统计记录
		eventCountService.save(new EventCount(request.getEno(), ModuleUtils.ITSM_REQUEST));
		request.setServiceDirectory(eventList);
		dto.setRequestCode(eventCode);
		//保存历史记录
		savaHistoryRecord(request, dto);
		if ( dto.getRequestClose() ) {
			LanguageContent lc = LanguageContent.getInstance();
			dto.setCloseCode(lc.getContent("label.rulePackage.requestRule"));
			closeRequest(request, dto);
		}
		Map<String, String> map =new HashMap<String, String>();
		map.put("id", request.getEno()+"");
		map.put("title", request.getEtitle());
		map.put("code", request.getRequestCode());
		map.put("content", request.getEdesc());
		LuenceUtil.getInstance(MODULECATEGORY).add(map);
		return request.getEno();
	}
	
	@Transactional
	public void savaHistoryRecord(Request request,RequestDTO dto){
	       // 保存历史记录
			HistoryRecordDTO historyRecordDto = new HistoryRecordDTO();
			historyRecordDto.setEno(request.getEno());
			historyRecordDto.setEventType(ModuleUtils.ITSM_REQUEST);
			historyRecordDto.setCreatedTime(new Date());
			historyRecordDto.setOperator(dto.getCreator());
			if (dto.getActionName() != null)
				historyRecordDto.setLogTitle(dto.getActionName());
			else {
				LanguageContent lc = LanguageContent.getInstance();
				historyRecordDto.setLogTitle(lc.getContent("common.add"));
			}
			historyRecordService.saveHistoryRecord(historyRecordDto);
	}
	/**
	 * 开启流程
	 */
	@Transactional
	public String openProcess(ProcessHandleDTO phDTO){
		Request request = requestDAO.findById(phDTO.getEno());
		RequestDTO requestDTO = new RequestDTO();
		if(StringUtils.hasText(request.getPid())){
			// 得到历史流程实例
			ProcessHistoriesDTO phdto = bpi.findHistoryProcessInstanceByPid(request.getPid());
			requestDTO.setProcessKey(phdto.getProcessDefinitionId());
		}
		
		entity2dto(request, requestDTO);
		//启动流程
		startProcessInstance(request, requestDTO ,phDTO);
		if (request.getResponsesTime() == null) {
			request.setResponsesTime(new Date());
			// 更新SLA状态(Tan)
			String slaStatus = getSlaStatus(request);
			request.setSlaState(dataDictionaryItemsDAO.findUniqueBy("dno", slaStatus));
			// 对应的通知规则
			requestProcessNotice(INoticeRuleService.REQUEST_RESPONSES_NOTIC, request, null, null, null, requestDTO.getCurrentUser(), null, null);
		}
		request.setFlowStart(true);
		requestDAO.merge(request);
		// 保存历史记录
		HistoryRecordDTO historyRecordDto = new HistoryRecordDTO();
		historyRecordDto.setEno(request.getEno());
		historyRecordDto.setEventType(ModuleUtils.ITSM_REQUEST);
		historyRecordDto.setCreatedTime(new Date());
		historyRecordDto.setOperator(appctx.getCurrentLoginName());
		LanguageContent lc = LanguageContent.getInstance();
		historyRecordDto.setLogTitle(lc.getContent("label.requestDetail.openProcess"));
		historyRecordDto.setLogDetails(phDTO.getRemark());
		historyRecordService.saveHistoryRecord(historyRecordDto);
		return request.getPid();
	}
	
	
	
	/**
	 * 启动流程实例
	 * @param request
	 * @param dto
	 */
	@Transactional
	private void startProcessInstance(Request request,RequestDTO dto,ProcessHandleDTO phDTO){
		Long eventId = null;
		if( request.getRequestCategory()!=null){
			eventId = request.getRequestCategory().getEventId();
		}
		String tgId = "";
		if(request.getAssigneeGroup()!=null){
			tgId = request.getAssigneeGroup().getOrgNo().toString();
		}
		final String belongsGroupIds = tgId;
		final Long categoryId = eventId;
		class AssignByBusy implements ICustomAssign{
			public Object execute(){
				return automaticallyAssignedByBusy(categoryId,belongsGroupIds,null);
			}
		}
		if(dto.getApprovalNo()==null){
			dto.setApprovalNo(0L);
		}
		dto.setEno(request.getEno());
		dto.setPid(request.getPid());
		dto.setEventCode(request.getEventCode());
		if(request.getLocation()!=null){
			dto.setLocationNos(request.getLocation().getEventId());
		}
		String pid = bpi.startFlowInstance(ModuleUtils.ITSM_REQUEST,dto.getProcessKey(),dto);
		request.setPid(pid);
		//任务指派
		phDTO.setPid(pid);
		phDTO.setModule("request");
		
		Object bean = bpi.assignTask(phDTO, dto, new AssignByBusy());
		// 修改请求状态
		updateRequestStatus(request.getEno(), request.getPid());
		//更新指派
		updateAssign(request,bean);
	}

	/**
	 * 判断SLA是否过期
	 * @param slaRule
	 * @return
	 */
	private boolean slaExpired(SLARule slaRule) {
		boolean result =false;
		if (slaRule != null && slaRule.getSlaContract() != null) {
			SLAContract slaContract = slaRule.getSlaContract();
			//判断是否过期
			if (slaContract != null && slaContract.getEndTime() != null && slaContract.getEndTime().getTime() < new Date().getTime()) {
				result = true;
			}
		}
		return result;
	}

	/**
	 * 请求编辑
	 * @param dto
	 */
	@Transactional
	public void updateRequest(RequestDTO dto) {
		Request request = requestDAO.findById(dto.getEno(), null);
		dto.setFlowStart(request.getFlowStart());
		dto2entity(dto, request);
		//解决方案
		if (StringUtils.hasText(dto.getSolutions())) {
			request.setSolutions(dto.getSolutions());
		}
		//请求状态
		if (dto.getStatusNo() != null) {
			request.setStatus(dataDictionaryItemsDAO.findById(dto.getStatusNo()));
		} else {
			request.setStatus(null);
		}
		// 保存历史记录
		HistoryRecordDTO historyRecordDto = new HistoryRecordDTO();
		historyRecordDto.setEno(request.getEno());
		historyRecordDto.setEventType(ModuleUtils.ITSM_REQUEST);
		historyRecordDto.setCreatedTime(new Date());
		historyRecordDto.setOperator(dto.getCreator());
		historyRecordDto.setLogTitle(dto.getActionName());
		LanguageContent lc = LanguageContent.getInstance();
		historyRecordDto.setLogDetails(lc.getContent("common.edit")+lc.getContent("title.mainTab.request"));
		historyRecordService.saveHistoryRecord(historyRecordDto);
		
		//服务目录
		List<EventCategory> eveList = new ArrayList<EventCategory>();
		if (dto.getServiceDirIds() != null && dto.getServiceDirIds().length > 0) {
			for (int i = 0; i < dto.getServiceDirIds().length; i++) {
				EventCategory eve = new EventCategory();
				eve = eventCategoryDAO.findById(dto.getServiceDirIds()[i]);
				eveList.add(eve);
			}
			request.setServiceDirectory(eveList);
		}
		requestDAO.merge(request);
		// 扩展属性
		saveAttr(dto, request);
		// 请求更新通知
		requestProcessNotice(INoticeRuleService.REQUEST_UPDATE_NOTICE, request, null, null, null, dto.getCurrentUser(), null, null);

		reFitSLA(SLAFITTYPE_RULESMATCH_SIGN, request.getEno(), null, null);
		
		Map<String, String> map =new HashMap<String, String>();
		map.put("id", request.getEno()+"");
		map.put("title", request.getEtitle());
		map.put("code", request.getRequestCode());
		map.put("content", request.getEdesc());
		LuenceUtil.getInstance(MODULECATEGORY).update(map);
	}

	/**
	 * 保存历史数据.
	 * @param nos
	 */
	@SuppressWarnings("unused")
	@Deprecated
	private void saveHistoryData(Long[] nos) {
		// 备份数据
		if (nos != null && nos.length > 0) {
			for (Long id : nos) {
				try {
					Request req = requestDAO.findById(id);
					RequestDTO dto = new RequestDTO();
					RequestDTO.entity2dto(req, dto);
					if (req.getCreatedBy() != null) {// 创建人
						dto.setCreatedByNo(req.getCreatedBy().getUserId());
					}
					if (req.getOwner() != null) {// 负责人
						dto.setOwnerNo(req.getOwner().getUserId());
					}
					if (req.getServicesOrg() != null) {// 服务机构
						dto.setServicesNo(req.getServicesOrg().getOrgNo());
					}
					if (req.getStatus() != null) {// 请求状态
						dto.setStatusNo(req.getStatus().getDcode());
					}
					if (req.getApprovalName() != null) {// 审批人
						dto.setApprovalName(req.getApprovalName());
					}
					if (req.getPid() != null) {// 流程编号
						dto.setPid(req.getPid());
					}
					if (req.getAssigneeGroup() != null) {// 指派组
						dto.setAssigneeGroupNo(req.getAssigneeGroup().getOrgNo());
					}
					if (req.getTechnician() != null) {// 指派技术员
						dto.setAssigneeNo(req.getTechnician().getUserId());
					}
					if (req.getPriority() != null) {// 优先级
						dto.setPriorityNo(req.getPriority().getDcode());
					}
					if (req.getRelatedConfigureItems() != null) {// 关联配置项
						Long[] cis = new Long[req.getRelatedConfigureItems().size()];
						int i = 0;
						for (CI ci : req.getRelatedConfigureItems()) {
							cis[i] = ci.getCiId();
							i++;
						}
						dto.setRelatedConfigureItemNos(cis);
					}
					if (req.getRequestCategory() != null) {// 请求分类
						dto.setRequestCategoryNo(req.getRequestCategory().getEventId());
					}
					if (req.getResponsesTime() != null) {// 响应时间
						dto.setRequestResponseTime(req.getResponsesTime());
					}
					if (req.getMaxResponseTime() != null) {// 响应时间
						dto.setMaxResponseTime(req.getMaxResponseTime());
					}
					if (req.getMaxCompleteTime() != null) {// 最迟完成时间
						dto.setMaxCompleteTime(req.getMaxCompleteTime());
					}
					if (req.getMaxCompleteTimeBack() != null) {
						dto.setMaxCompleteTimeBack(req.getMaxCompleteTimeBack());
					}
					if (req.getRequestResolvedTime() != null) {// 完成时间
						dto.setRequestResolvedTime(req.getRequestResolvedTime());
					}
					if (req.getSlaState() != null) {// SLA状态

						dto.setSlaStatusNo(req.getSlaState().getDcode());
					}
					HistoryDataDTO historyDataDTO = new HistoryDataDTO(id, MODULECATEGORY, dto.getEtitle(), JSONUtil.serialize(dto));
					historyDataService.saveHistoryData(historyDataDTO);

				} catch (JSONException e) {
					throw new ApplicationException("ERROR_CONVERT_DTO_TO_JSON/n", e);
				}
			}
		}
	}

	/**
	 * 请求删除
	 * @param ids
	 */
	@Transactional
	public void deleteRequests(Long[] ids) {
		List<Request> list = requestDAO.findByIds(ids);
		for (Request request : list) {
			if(request.getFlowStart() && request.getPid()!=null){
				if (bpi.isEnded(request.getPid()))
					bpi.deleteProcessInstance(request.getPid());
				else
					bpi.deleteProcessInstanceCascade(request.getPid());
			}
		}
		// saveHistoryData(ids);// 保存历史数据
		requestDAO.deleteByIds(ids);
	}

	/**
	 * 请求统计(左边二级菜单显示统计)
	 * @param qdto
	 * @return RequestCountResultDTO
	 */
	@Transactional
	public RequestCountResultDTO countRequest(RequestQueryDTO qdto) {
		qdto=structureQueryDTO(qdto);//RequestQueryDTO构造
		qdto.setCurrentUser(qdto.getLoginName());
		RequestCountResultDTO rcrd = new RequestCountResultDTO();
		// 全部请求 orgno
		rcrd.setCountAllRquest(requestDAO.countRequestByType(qdto));
			// 我提出的请求
		qdto.setCountQueryType("myProposedRequest");
		rcrd.setCountMyRquest(requestDAO.countRequestByType(qdto));
		qdto.setCountQueryType(null);
			// 指派给我的请求
		qdto.setCountQueryType("assigneeToMyRequest");
		rcrd.setCountMyPeRquest(requestDAO.countRequestByType(qdto));
		qdto.setCountQueryType(null);
			// 我负责的请求
		qdto.setCountQueryType("myOwnerRequest");
		rcrd.setCountMyOwRquest(requestDAO.countRequestByType(qdto));
		qdto.setCountQueryType(null);
			// 我描述不全、未提交的请求
		qdto.setCountQueryType("myNotComprehensiveNotSubmitted");
		rcrd.setMyNotComprehensiveNotSubmittedRequest(requestDAO.countRequestByType(qdto));
		qdto.setCountQueryType(null);
			// 代理给我的请求统计
		qdto.setCountQueryType("actingToMyRequest");
		rcrd.setCountactingToMyRequest(requestDAO.countRequestByType(qdto));
		qdto.setCountQueryType(null);
		// 我们组提出的请求 
		qdto.setCountQueryType("myGroupProposedRequest");
		rcrd.setCountMyGroupProposedRequest(requestDAO.countRequestByType(qdto));
		qdto.setCountQueryType(null);
		// 指派给我组的请求
		qdto.setCountQueryType("assigneeGroupRequest");
		qdto.setAssigneeGroupNo(qdto.getOrgNo());
		rcrd.setCountMyGrRquest(requestDAO.countRequestByType(qdto));
		qdto.setAssigneeGroupNo(null);
		qdto.setCountQueryType(null);
			// 我未开始处理的请求
		qdto.setCountQueryType("nohandle");
		rcrd.setCountMyNoHandleRequest(requestDAO.countRequestByType(qdto));
		qdto.setCountQueryType(null);
			// 我正在处理的请求
		qdto.setCountQueryType("handle");
		rcrd.setCountMyIngHandleRequest(requestDAO.countRequestByType(qdto));
		qdto.setCountQueryType(null);
			// 我已完成的请求
		qdto.setCountQueryType("complete");
		rcrd.setCountMyCompleteHandleRequest(requestDAO.countRequestByType(qdto));
		qdto.setCountQueryType(null);
			// 我已关闭的请求
		qdto.setCountQueryType("close");
		rcrd.setCountMyCloseHandleRequest(requestDAO.countRequestByType(qdto));
		qdto.setCountQueryType(null);
		return rcrd;
	}

	/**
	 * 请求流程任务统计
	 * @param qdto
	 * @return RequestCountResultDTO
	 */
	@Transactional
	public RequestCountResultDTO countRequestFlowTask(RequestQueryDTO qdto) {
		RequestCountResultDTO rcrd = new RequestCountResultDTO();
		if (qdto.getLoginName() != null) {
			rcrd.setCountMyRequestTask(bpi.countPersonalTasks(qdto.getLoginName()));
			rcrd.setCountMyGroupRequestTask(bpi.countGroupTasks(qdto.getLoginName()));
			rcrd.setCountMyProcessedTask(bpi.countMyProcessedTask(qdto.getLoginName()));
			rcrd.setActingmyOutstandingTasks(jbpmTaskDAO.countJbpmTask(qdto.getLoginName()));
		}
		return rcrd;
	}

	/**
	 * dto2entity
	 * @param dto
	 * @param request
	 */
	public void dto2entity(RequestDTO dto, Request request) {
		dto.setUpgradeApplySign(request.getUpgradeApplySign());
		dto.setHang(request.getHang());
		dto.setResponsesTime(request.getResponsesTime());
		dto.setCreatedOn(request.getCreatedOn());
		dto.setServiceDirectory(request.getServiceDirectory());
		RequestDTO.dto2entity(dto, request);
		//创建时间
		if(request.getCreatedOn()==null){
			request.setCreatedOn(new Date());
		}
		
		if(StringUtils.hasText(dto.getRequestCode())){
			request.setEventCode(dto.getRequestCode());
		}
		//服务机构
		if (dto.getServicesNo()!=0) {
			request.setServicesOrg(organizationServicesDAO.findById(dto.getServicesNo()));
		}
		//保存SLA规则
		if (dto.getSlaNo() != null) {
			request.setSlaRule(slaRuleDAO.findById(dto.getSlaNo()));
		}
		//需要审批的
		if (dto.getApprovalNo() != 0) {
			User user = userDAO.findById(dto.getApprovalNo());
			if (user != null) {
				dto.setApprovalName(user.getLoginName());
			}
		}
		// 请求状态,新建，审批中
		if (dto.getApprovalNo() != 0) {
			request.setApprovalState("WaitApproval");
		}
		//创建人
		User user = null;
		if (dto.getCreatedByNo() != null) {
			user = userDAO.findById(dto.getCreatedByNo());
		} else if (StringUtils.hasText(dto.getCreatedByName())) {
			user = userDAO.findUniqueBy("loginName", dto.getCreatedByName());
		}
		if (user != null) {
			request.setCreatedBy(user);
		}
		
		//影响范围
		if (dto.getEffectRangeNo() != null) {
			request.setEffectRange(dataDictionaryItemsDAO.findById(dto.getEffectRangeNo()));
		} else {
			request.setEffectRange(null);
		}
		//紧急度
		if (dto.getSeriousnessNo() != null) {
			request.setSeriousness(dataDictionaryItemsDAO.findById(dto.getSeriousnessNo()));
		} else {
			request.setSeriousness(null);
		}
		//优先级
		if (dto.getPriorityNo() != null) {
			request.setPriority(dataDictionaryItemsDAO.findById(dto.getPriorityNo()));
		} else {
			request.setPriority(null);
		}
		//来源
		if (dto.getImodeNo() != null) {
			request.setImode(dataDictionaryItemsDAO.findById(dto.getImodeNo()));
		} else {
			request.setImode(null);
		}
		//级别
		if (dto.getLevelNo() != null) {
			request.setLevel(dataDictionaryItemsDAO.findById(dto.getLevelNo()));
		} else {
			request.setLevel(null);
		}
		// 请求分类
		if (dto.getRequestCategoryNo() != null) {
			EventCategory eventCategory = eventCategoryDAO.findById(dto.getRequestCategoryNo());
			if (eventCategory != null) {
				request.setRequestCategory(eventCategory);
				request.setEventCategory(eventCategory);
				// 如果请求分类不为空，则使用分类定义的规则编码
				if(StringUtils.hasText(eventCategory.getCategoryCodeRule())){
					String eventCode = request.getRequestCode();// 旧的请求编码
					if(StringUtils.hasText(eventCode)){
						eventCode = eventCode.replaceAll(eventCode.substring(0, eventCode.lastIndexOf("-")), eventCategory.getCategoryCodeRule());// 更新请求编码
						request.setRequestCode(eventCode);// 赋值于分类规则
					}
					
				}
			}
		} else {
			request.setRequestCategory(null);
		}
		//服务目录
		if (StringUtils.hasText(dto.getServiceDirIdsStr())) {
			String[] dirIds = dto.getServiceDirIdsStr().split(",");
			Long[] dirIdsL = new Long[dirIds.length];
			for (int i = 0; i < dirIds.length; i++) {
				String str = dirIds[i];
				dirIdsL[i] = Long.parseLong(str);
			}
			dto.setServiceDirIds(dirIdsL);
		}
		if (dto.getRequestServiceDirNo() != null) {
			EventCategory eventCategory = eventCategoryDAO.findById(dto.getRequestServiceDirNo());
			if (eventCategory != null) {
				request.setRequestServiceDirectory(eventCategory);
			}
		}
		//关联配置项
		if (dto.getRelatedConfigureItemNos() != null) {
			List<CI> cis = new ArrayList<CI>();
			for (Long cid : dto.getRelatedConfigureItemNos()) {
				CI ci = ciDAO.findById(cid);
				cis.add(ci);
			}
			request.setRelatedConfigureItems(cis);
		} else
			request.setRelatedConfigureItems(null);
		
		//技术员
		if (dto.getAssigneeNo() != null) {
			User technician = userDAO.findById(dto.getAssigneeNo());
			if (technician != null) {
				request.setTechnician(technician);
			}
		}
		//技术员
		if (dto.getTechnicianNo() != null) {
			User technician = userDAO.findById(dto.getTechnicianNo());
			if (technician != null) {
				request.setTechnician(technician);
			}
		}
		//技术组
		if (dto.getAssigneeGroupNo() != null) {
			Organization inner = organizationDAO.findById(dto.getAssigneeGroupNo());
			if (inner != null) {
				request.setAssigneeGroup(inner);
			}
		}
		//地点
		if(dto.getLocationNos()!=null){
			EventCategory locaction = eventCategoryDAO.findById(dto.getLocationNos());
			if(locaction!=null){
				request.setLocation(locaction);
			}
		}
	}

	/**
	 * 通知请求用户.
	 * @param request
	 * @param dto
	 */
	@Transactional
	public void addRequestNotice(Request request, RequestDTO dto) {
		// 自动指派通知技术员
		if(request.getTechnician()!=null)
		requestProcessNotice(INoticeRuleService.REQUEST_ASSIGN_NOTICE, request, null, null, null, dto.getCurrentUser(), null, null);
		// 自助创建请求通知
		requestProcessNotice(INoticeRuleService.REQUEST_SELF_CREATE_REQUEST_NOTICE, request, null, null, null, dto.getCurrentUser(), null, null);
		// 服务台接收到邮件自动回复请求人
		requestProcessNotice(INoticeRuleService.REQUEST_RECEIVE_REQUEST_REPLY_REQUESTER, request, null, null, null, dto.getCurrentUser(), null, null);
		// 有新的请求通知服务台
		requestProcessNotice(INoticeRuleService.REQUEST_NEW_REQUEST_NOTICE_HELPDESK, request, null, null, null, dto.getCurrentUser(), null, null);
	}

	/**
	 * 请求匹配规则(包括优先级矩阵)
	 * @param dto
	 */
	@Transactional
	private void requestRuleMatch(RequestDTO dto) throws NullPointerException {
		if (dto.getOrganizationNo() == null) {
			dto.setOrganizationNo(dto.getCompanyNo());
		}
		dto.setOrganizationNos(organizationService.reverFindOrg(new Long[] { dto.getOrganizationNo() }));
		String edesc = dto.getEdesc();
		dto.setEdesc(HtmlSpirit.delHTMLTag(edesc));
		// 套用请求规则，取得Services
		// 允许请求人和技术员覆盖已有的优先级矩阵
		String[] rulePackageNames = null;
		PriorityMatrixStatus pms = priorityMatrixStatusDAO.findUniqueBy("type", "priorityMatrixStatus");
		if (pms != null && "true".equals(pms.getPriorityMatrixStatus()) && dto.getPriorityNo() != null) {
			rulePackageNames = new String[] {RulePackage.REQUESTFITSERVICES};
		} else {
			rulePackageNames = new String[] {RulePackage.REQUESTFITSERVICES, RulePackage.PRIORITYMATRIX};
		}
		droolsFacade.matchRule(dto, rulePackageNames,RulePathType.Request.getValue(),RulePathFile.URL_SETREQUESTRULESOURCE.getValue());
		dto.setEdesc(edesc);
	}
	/**
	 * 查找匹配的SLARule
	 * @param dto
	 * @param sc
	 * @return SLARule
	 */
	@Transactional
	private SLARule findMatchRule(RequestDTO dto,SLAContract sc){
		SLARuleQueryDTO slaQueryDto = new SLARuleQueryDTO();
		slaQueryDto.setContractNo(sc.getContractNo());
		slaQueryDto.setRuleName(dto.getMatchRuleName());
		SLARule slaRule = slaRuleDAO.findUniqueSLARule(slaQueryDto);
		return slaRule;
	}
	/**
	 * 运行匹配规则
	 */
	@Transactional
	private RequestDTO runMatchRule(RequestDTO dto,SLAContract sc){
		dto.setServicesNo(sc.getServiceOrg().getOrgNo());
		String edesc = dto.getEdesc();
		dto.setEdesc(HtmlSpirit.delHTMLTag(edesc));
		// 取得SLA对应包的包名
		final String rulePackageName = sc.getRulePackage().getPackageName();
		// 运行规则，取得对应的规则名称.
		droolsFacade.matchRule(dto, new String[] {rulePackageName },RulePathType.Sla.getValue(),RulePathFile.URL_SETSLARULESOURCE.getValue());
		dto.setEdesc(edesc);
		return dto;
	}
	/**
	 * SLARule To RequestDTO
	 * @param sc
	 * @param slaRule
	 * @param dto
	 * @return RequestDTO
	 */
	@Transactional
	private RequestDTO entity2dto(SLAContract sc,SLARule slaRule,RequestDTO dto){
		if (slaRule == null) {
			throw new ApplicationException(
					"ERROR_CAN_NOT_FIT_SLA_RULE\n" + sc.toString());
		} else {
			// 关联SLA到请求
			dto.setSlaNo(slaRule.getRuleNo());
			dto.setMatchRuleName(slaRule.getRuleName());
		}
		return dto;
	}

	/**
	 * 获取匹配SLA Rule
	 * 
	 * @param dto
	 */
	@Transactional
	private RequestDTO getRequestFitSlaRule(RequestDTO dto) {
		if (dto.getCreatedByNo() != null && dto.getCreatedByNo() != 0) {
			// 请求人所在机构编号
			User requester = userDAO.findById(dto.getCreatedByNo());
			if (requester != null && requester.getOrgnization() != null) {
				// 请求人所在机构编号
				SLAContract sc = null;
				// 根据请求者所在机构和服务机构确定一个唯一的SLA
				if (dto.getSlaContractNo() != null) {
					sc = slaContractDAO.findById(dto.getSlaContractNo());
				}
				if (sc == null) {// 匹配不到使用默认的SLA
					sc = slaContractDAO.findUniqueBy("isDefault", true);
				}
				if (sc == null) {// 无法根据服务机构和被数据机构匹配到相应的SLA.
					throw new ApplicationException("ERROR_FITSLA_Default\n");
				}else{
					dto = runMatchRule(dto, sc);
					SLARule slaRule = findMatchRule(dto, sc);
					dto = entity2dto(sc, slaRule, dto);
				}
			} else {
				throw new ApplicationException("ERROR_USER_ORGANIZATION_NULL\n");// 请求创建用户的所属机构不能为空.
			}
		} else {
			throw new ApplicationException("ERROR_CREATE_BY_NULL\n");// 创建用户不能为空.
		}
		return dto;
	}

	/**
	 * 计算SLA时间.
	 * RequestDTO 必须字段值：slaNo,createdOn
	 * @param dto
	 */
	@Transactional
	private void calcRequestSLATime(RequestDTO dto) {
		// 查找SLA详情
		SLARule slaRule = slaRuleDAO.findById(dto.getSlaNo());
		if (slaRule != null) {
			dto.setResponseTime(slaRule.getRespondTime() * 1000L);
			dto.setCompleteTime(slaRule.getFinishTime() * 1000L);
			// 创建时间
			Long createTime = new Date().getTime();
			if (dto.getCreatedOn() != null) {
				createTime = dto.getCreatedOn().getTime();
			}
			
			// 未排除节假日
			if (slaRule.getIncludeHoliday()) {
				dto.setMaxResponseTime(createTime + dto.getResponseTime());
				dto.setMaxCompleteTime(createTime + dto.getCompleteTime());
			} else {
				Long serviceNo = slaRule.getSlaContract().getServiceOrg().getOrgNo();
				// SLA时间计算
				List<Holiday> holidays = holidayDAO.findHolidayByServicesNo(serviceNo);
				ServiceTime serviceTime = serviceTimeDAO.findByOrgNo(serviceNo);
				if (serviceTime != null) {
					WorkingTimeDTO workingTimeDto = new WorkingTimeDTO(holidays, serviceTime);
					// 计算响应时间
					Long trueResponseTime = calcPredictTimeUtils.calcPredictTime(dto.getResponseTime(), createTime, workingTimeDto, null, null);
					// 计算完成时间
					Long trueCompleteTime = calcPredictTimeUtils.calcPredictTime(dto.getCompleteTime(), createTime, workingTimeDto, null, null);
					// 设置DTO
					dto.setMaxResponseTime(trueResponseTime);
					dto.setMaxCompleteTime(trueCompleteTime);
				} else {
					throw new ApplicationException("ERROR_SLA_SERVICETIME_IS_NULL");
				}
			}
		} else {
			throw new ApplicationException("ERROR_SLA_RULENAME_IS_NULL");
		}
	}

	/**
	 * 解除挂起重新计算SLA
	 * @param eno
	 * @param pendingDateStart 挂起开始时间
	 * @param pendingDateEnd 挂起结束时间
	 */
	@Transactional
	public void removePendingReCalcRequestSLATime(Long eno, Date pendingDateStart, Date pendingDateEnd) {
		Request request = requestDAO.findById(eno);
		// 查找SLA详情
		SLARule slaRule = request.getSlaRule();
		if (slaRule != null) {
			Long responseTime = slaRule.getRespondTime() * 1000L;
			Long completeTime = slaRule.getFinishTime() * 1000L;
			// 未排除节假日
			if (slaRule.getIncludeHoliday()) {
				request.setMaxResponseTime(request.getCreatedOn().getTime() + responseTime + (pendingDateEnd.getTime() - pendingDateStart.getTime()));
				request.setMaxCompleteTime(request.getCreatedOn().getTime() + completeTime + (pendingDateEnd.getTime() - pendingDateStart.getTime()));
			} else {
				if(request.getServicesOrg()==null){
					request.setServicesOrg(slaRule.getSlaContract().getServiceOrg());
				}
				// SLA时间计算
				List<Holiday> holidays = holidayDAO.findHolidayByServicesNo(request.getServicesOrg().getOrgNo());
				ServiceTime serviceTime = serviceTimeDAO.findByOrgNo(request.getServicesOrg().getOrgNo());
				if (serviceTime != null) {
					WorkingTimeDTO workingTimeDto = new WorkingTimeDTO(holidays, serviceTime);
					// 计算响应时间
					Long trueResponseTime = calcPredictTimeUtils.calcPredictTime(responseTime, request.getCreatedOn().getTime(), workingTimeDto, pendingDateStart, pendingDateEnd);
					request.setMaxResponseTime(trueResponseTime);
					// 计算完成时间
					Long trueCompleteTime = calcPredictTimeUtils.calcPredictTime(completeTime, request.getCreatedOn().getTime(), workingTimeDto, pendingDateStart, pendingDateEnd);
					request.setMaxCompleteTime(trueCompleteTime);
				} else {
					throw new ApplicationException("ERROR_SLA_SERVICETIME_IS_NULL");
				}
			}
		} else {
			throw new ApplicationException("ERROR_SLA_RULENAME_IS_NULL");
		}
	}
	/**
	 * dto to entity
	 * @param dto
	 * @param request
	 */
	@Transactional
	private Request setSla(RequestDTO dto, Request request){
		if (dto.getSlaNo() != null) {
			SLARule slaRule = slaRuleDAO.findById(dto.getSlaNo());
			request.setSlaRule(slaRule);
			// SLA是否过期
			request.setSlaExpired(slaExpired(slaRule));
			dto.setMatchRuleName(slaRule.getRuleName());
		}
		if(!request.getHang()){//非挂起状态
			request.setMaxResponseTime(dto.getMaxResponseTime());
			request.setMaxCompleteTime(dto.getMaxCompleteTime());
		}else{//挂起状态
			request.setMaxResponseTime(null);
			request.setMaxCompleteTime(null);
		}
		return request;
	}

	/**
	 * 保存解决方案
	 * @param dto
	 */
	@SuppressWarnings("unchecked")
	@Transactional
	public void saveSolutions(RequestDTO dto) {
		
		//sun 统计知识库的引用条数
		if(StringUtils.hasText(dto.getSolutions())&&dto.getKnowledgeNo()!=null&&dto.getKnowledgeNo()!=0l){
			KnowledgeInfo knowentity=knowledgeDAO.findById(new Long(dto.getKnowledgeNo()));
			if(knowentity!=null){
				if(null!=knowentity.getCount()){
					knowentity.setCount(knowentity.getCount()+1);
				}else{
					knowentity.setCount(new Long(1));
				}
				knowledgeDAO.merge(knowentity);
			}
		}
		//end
		Request request = requestDAO.findById(dto.getEno());
		request.setSolutions(dto.getSolutions());
		if (dto.getOffmodeNo() != null && request.getOffmode() == null) {// 请求处理方式
			DataDictionaryItems Offmode = dataDictionaryItemsDAO.findById(dto.getOffmodeNo());
			if (Offmode != null) {
				request.setOffmode(Offmode);
			}
		}
		Comment comment = null;

		if (request.getRequestSolutions() != null) {
			comment = request.getRequestSolutions();
			List<Attachment> attachs = comment.getAttachments();
			List<Attachment> newAttachs = attachmentService.saveAttachment(dto.getAttachmentStr(), ModuleUtils.ITSM_REQUEST);
			attachs = (List<Attachment>) CollectionUtils.union(newAttachs, attachs);
			comment.setAttachments(attachs);
		} else {
			comment = new Comment();
			comment.setAttachments(attachmentService.saveAttachment(dto.getAttachmentStr(), ModuleUtils.ITSM_REQUEST));
		}

		comment.setRemark(dto.getSolutions());
		request.setRequestSolutions(commentDAO.merge(comment));

		requestDAO.save(request);
	}
	
	// 请求批量关闭
	@Transactional
	public void requestBatchClose(RequestDTO requestDTO) {
		if ( requestDTO.getEnos()!=null) {
			Long[] enos=requestDTO.getEnos();
			LanguageContent lc = LanguageContent.getInstance();
			
			HistoryRecordDTO hrDTO =new HistoryRecordDTO();
			String title=lc.getContent("lable.requestBatchClose",appctx.getCurrentLanguage());
			hrDTO.setLogTitle(title);
			hrDTO.setOperator(appctx.getCurrentLoginName());
			for (int i = 0; i < enos.length; i++) {
				//if(i>0){
					requestDTO.setEno(enos[i]);
					hrDTO.setLogDetails(title+"  ID:"+Arrays.toString(requestDTO.getRequestCodes())+"<br>"+requestDTO.getRemark());
					saveHistoryRecord(enos[i], hrDTO);
					requestActionService.requestDirectClose(requestDTO);
				//}
			}
		}
	}
	
	/**
	 * 直接关闭此请求，
	 * @param request
	 * @param requestDTO
	 */
	private void closeRequest(Request request,RequestDTO requestDTO){
		if(StringUtils.hasText(requestDTO.getPid()) && requestDTO.getFlowStart() 
				&& !bpi.isEnded(requestDTO.getPid())){
			try {
				bpi.endProcessInstance(requestDTO.getPid());
			} catch (Exception e) {
				LOGGER.error("REQUESTSERVICE_CLOSEREQUEST_ERROR",e);
			}
		}
		// 响应时间
		if (request.getResponsesTime() == null) {
			request.setResponsesTime(new Date());
		}
		// 完成时间
		request.setRequestResolvedTime(new Date());

		//request.setIsFCR(true);
		request.setStatus(dataDictionaryItemsDAO.findUniqueBy("dno","request_close"));
		if (request.getStatus() == null){
			throw new ApplicationException("ERROR_REQUEST_STATUS_IS_NULL");
		}
		
		// //关闭时间
		request.setCloseTime(new Date());
		LanguageContent lc = LanguageContent.getInstance();
		request.setCloseCode(requestDTO.getCloseCode());
		if (request.getSolutions() != null) {
			request.setSolutions(request.getSolutions()+ requestDTO.getSolutions());
		} else {
			request.setSolutions(requestDTO.getSolutions());
		}
		// SLA状态
		String slaStatus = getSlaStatus(request);
		request.setSlaState(dataDictionaryItemsDAO.findUniqueBy("dno",
				slaStatus));
		
		requestDAO.merge(request);
		requestDTO.setActionName( lc.getContent("common.close") );
		savaHistoryRecord(request, requestDTO);
	}
	/**
	 * 请求动作
	 * 
	 * @param requestDTO
	 * @param hrDTO
	 */
	@Transactional
	public void requestAction(RequestDTO requestDTO, HistoryRecordDTO hrDTO) {
		// 保存操作记录
		saveHistoryRecord(requestDTO.getEno(), hrDTO);
		String optType = requestDTO.getOptType();
		// 请求处理备注
		if ("requestDealRemark".equals(optType)) {
			Request request = requestDAO.findById(requestDTO.getEno());
			requestProcessNotice(INoticeRuleService.REQUEST_ADD_COMMENT_NOTICE, request, null, null, null, requestDTO.getCurrentUser(), null, null);
		}
		// 请求指派//指派二线//指派三线//指派四线
		if ("requestAssgin".equals(optType)) {
			requestActionService.requestAssgin(requestDTO);
		}
		// 请求提取
		if ("requestGet".equals(optType)) {
			requestActionService.requestGet(requestDTO);
		}
		// 请求升级
		if ("requestUpgrade".equals(optType)) {
			requestActionService.requestUpgrade(requestDTO);
		}
		// 请求升级申请
		if ("requestUpgradeApply".equals(optType)) {
			Request request = requestDAO.findById(requestDTO.getEno());
			request.setUpgradeApplySign(1L);
			requestDAO.merge(request);
		}
		// 请求回访
		if ("requestVisit".equals(optType) || "requestVisit_re".equals(optType)) {
			requestActionService.requestVisit(requestDTO);
		}
		// 再指派
		if ("requestAgainAssgin".equals(optType)) {
			requestActionService.requestAgainAssgin(requestDTO);
		}
		// 请求直接关闭(自行解决)
		if ("requestDirectClose".equals(optType)) {
			requestActionService.requestDirectClose(requestDTO);
		}
		// 请求挂起与解除挂起
		if ("requestHangRemove".equals(optType)) {
			requestActionService.requestHangRemove(requestDTO);
		}
		// 修改SLA时间(功能已注释)
		if ("editRequestSlaTime".equals(optType)) {
			requestActionService.editRequestSlaTime(requestDTO);
		}
		// reopen
		if ("reopen".equals(optType)) {
			Request request = requestDAO.findById(requestDTO.getEno());
			request.setStatus(dataDictionaryItemsDAO.findUniqueBy("dno", "request_processReopen"));
			request.setRequestResolvedTime(null);
			request.setCloseTime(null);
			request.setVisitRecord(null);
			request.setTechnician(null);
			request.setResponsesTime(null);
			request.setAssigneeGroup(null);
			RequestDTO dto = new RequestDTO();
			User user = userDAO.findUniqueBy("loginName", request.getApprovalName());
			if(user!=null){
				dto.setApprovalName(user.getLoginName());
				dto.setApprovalNo(user.getUserId());
			}else{
				dto.setApprovalName(null);
				dto.setApprovalNo(0L);
			}
			request.setFlowStart(false);
			requestDAO.merge(request);
			//对应的通知规则
			requestProcessNotice(INoticeRuleService.REQUEST_REOPEN_NOITCE, request, null, null, null, requestDTO.getCurrentUser(), null, null);
		}
		
		// 请求描述不全、未提交
		if ("notComprehensiveNotSubmitted".equals(optType)) {
			Request request = requestDAO.findById(requestDTO.getEno(), null);
			request.setStatus(dataDictionaryItemsDAO.findUniqueBy("dno", "request_notComprehensiveNotSubmitted"));
			//SLA时间清空
			request.setMaxResponseTime(null);
			request.setMaxCompleteTime(null);
			//更新SLA状态
			String slaStatus = getSlaStatus(request);
			request.setSlaState(dataDictionaryItemsDAO.findUniqueBy("dno", slaStatus));
			
			requestDAO.merge(request);
			requestProcessNotice(INoticeRuleService.REQUEST_NOT_COMPREHEN_SIVE_NOTSUBMITTED_NOTICE, request, null, null, null, requestDTO.getCurrentUser(), null, null);
		}
		// 请求重新提交
		if ("reSubmit".equals(optType)) {
			Request request = requestDAO.findById(requestDTO.getEno());
			request.setStatus(dataDictionaryItemsDAO.findUniqueBy("dno", "request_new"));
			
			//重新计算SLA
			RequestDTO dto = new RequestDTO();
			dto.setCreatedOn(new Date());//以重新提交时间开始计算SLA
			dto.setSlaNo(request.getSLANo());
			calcRequestSLATime(dto);
			request = setSla(dto, request);
			
			//更新SLA状态
			String slaStatus = getSlaStatus(request);
			request.setSlaState(dataDictionaryItemsDAO.findUniqueBy("dno", slaStatus));
			
			requestDAO.merge(request);
			requestProcessNotice(INoticeRuleService.REQUEST_RESUBMIT_NOTICE, request, null, null, null, requestDTO.getCurrentUser(), null, null);
		}
	}

	/**
	 * 邮件回访保存
	 * @param eno
	 * @param visitRecord
	 * @return boolean
	 */
	@Transactional
	public boolean requestVisitByEmail(Long eno, String visitRecord) {
		boolean result=false;
		if (eno != null) {
			Request request = requestDAO.findById(eno);
			if (request.getVisitSign() != null && request.getVisitSign().equals("yes")) {
				result= false;
			} else {
				request.setVisitRecord(visitRecord);
				request.setVisitSign("yes");
				requestDAO.merge(request);
				result= true;
			}
		} else {
			result= false;
		}
		return result;
	}

	/**
	 * 保存历史记录
	 * @param eno
	 * @param historyRecordDTO
	 */
	@Transactional
	private void saveHistoryRecord(Long eno, HistoryRecordDTO historyRecordDTO) {
		historyRecordDTO.setCreatedTime(new Date());
		historyRecordDTO.setEno(eno);
		historyRecordDTO.setEventType(ModuleUtils.ITSM_REQUEST);
		historyRecordService.saveHistoryRecord(historyRecordDTO);
	}
	private String[] insert(String[] arr, String str)
    {
        int size = arr.length;
        
        String[] tmp = new String[size + 1];
        
        System.arraycopy(arr, 0, tmp, 0, size);
        
        tmp[size] = str;
        
        return tmp;
    }
	/**
	 * 根据PageDTO导出数据.
	 * 
	 * @param p
	 */
	@SuppressWarnings("unchecked")
	public void exportData(ExportPageDTO p) {
		List<String[]> data = new ArrayList<String[]>();
		ExportInfo entity = new ExportInfo();
		if(p!=null){
			LanguageContent lc = LanguageContent.getInstance();
			String lang = p.getLang();
			String[] strs=new String[] { 
    		        lc.getContent("common.id", lang),
    		        lc.getContent("label.report.request.title", lang),
    		        lc.getContent("label.user.description", lang),
    		        lc.getContent("tool.im.state", lang),
    		        lc.getContent("report.title_Classify", lang),
    		        lc.getContent("label.ci.ciServiceDir", lang),
    		        lc.getContent("label.belongs.client", lang),
    		        lc.getContent("title.requestor.org", lang),
    		       // lc.getContent("label.request.form", lang),
    		        lc.getContent("report.title_Priority", lang),
    		        //lc.getContent("label.request.complexity", lang),
    		        //lc.getContent("label.request.effect", lang),
    		        //lc.getContent("label.request.seriousness", lang),
    		        lc.getContent("label.request.requestUser", lang),
    		        lc.getContent("label.request.update", lang),
    		        //lc.getContent("label.request.withAssets", lang),
    		        lc.getContent("label.request.assignToGroup", lang),
    		        lc.getContent("title.change.assigneeTechnician", lang),
    		        lc.getContent("label.request.slaReuqestTime", lang),
    		        lc.getContent("label.request.slaCompleteTime", lang),
    		        lc.getContent("common.cerateTime", lang),
    		        lc.getContent("label.request.requestTime", lang),
    		        lc.getContent("label.request.completeTime", lang),
    		        lc.getContent("common.updateTime", lang),
    		        lc.getContent("label.dc.SLAStatus", lang),
    		        //lc.getContent("title.orgSettings.workTime", lang),
    		        //lc.getContent("title.totalCost", lang) + "(" + currencyService.findDefaultCurrency().getSign() + ")",
    		        lc.getContent("title.request.solutions", lang) 
		        };
			Field f=new Field();
			f.setModule("request");
			List<Field> fields=fieldDAO.findListField(f,true);
			for (Field field : fields) {
				if(field.getExport()){
					strs=insert(strs, field.getFieldName());
				}
			}
			data.add(strs);

			if (p.getData() != null && p.getData().size() > 0) {
				List<Request> entities = p.getData();
				for (Request request : entities) {
					//workTime = 0L;
					//cost = 0d;
					//actualCost(request);
					convertRequestToStringArray(request, data, workTime, cost, lang);
				}
			}
			entity = p.getEntity();
		}
		exportInfoService.exportCommonCSV(data, entity,p.getPath());
	}

	/**
	 * 根据条件查询出导出数据
	 * 
	 * @param dto
	 */
	@SuppressWarnings("rawtypes")
	public void commonExportData(ExportQueryDTO exportQueryDTO) {
		RequestQueryDTO dto=(RequestQueryDTO) exportQueryDTO.getQueryDTO();
		List datas = null;
		if (dto.getFilterId() != null) {
			datas = filterService.findByFilter(dto.getFilterId(), 0, CSVWriter.EXPORT_SIZE, dto.getSidx(), dto.getSord());
		} else if (dto!= null && StringUtils.hasText(dto.getAlias())) {
			try {
				dto.setLimit(CSVWriter.EXPORT_SIZE);
				dto=structureQueryDTO(dto);//RequestQueryDTO构造
				fullTextSearch(dto);
				datas = requestDAO.findRequest(dto, dto.getSidx(), dto.getSord());
			} catch (Exception e) {
				LOGGER.error(e);
			}
		} else {
			try {
				dto.setLimit(CSVWriter.EXPORT_SIZE);
				dto=structureQueryDTO(dto);//RequestQueryDTO构造
				datas = requestDAO.findRequest(dto, dto.getSidx(), dto.getSord());
			} catch (Exception e) {
				LOGGER.error(e);
			}
		}
		ExportPageDTO exportPageDTO = new ExportPageDTO();
		exportPageDTO.setLang(dto.getLang());
		exportPageDTO.setData(datas);
		exportPageDTO.setEntity(dto.getExportInfo());
		exportPageDTO.setTenantId(dto.getTenantId());
		exportPageDTO.setPath(exportQueryDTO.getPath());
		exportData(exportPageDTO);
	}

	/**
	 * 根据过滤器结果导出数据.
	 * 
	 * @param filterId
	 */
	@Transactional
	public void exportRequestItems(Long filterId, String sidx, String sord) {
		ExportInfo entity = exportInfoService.saveExportInfoReturnEntity(MODULECATEGORY);
		//LanguageContent lc = LanguageContent.getInstance();
		RequestQueryDTO requestQueryDTO = new RequestQueryDTO();
		String lang = appctx.getCurrentLanguage();
		requestQueryDTO.setLang(lang);
		requestQueryDTO.setExportInfo(entity);
		requestQueryDTO.setSidx(sidx);
		requestQueryDTO.setSord(sord);
		requestQueryDTO.setFilterId(filterId);
		requestQueryDTO.setTenantId(appctx.getCurrentTenantId());
		
		ExportQueryDTO exportQueryDTO=new ExportQueryDTO();
		exportQueryDTO.setTenantId(appctx.getCurrentTenantId());
		exportQueryDTO.setQueryDTO(requestQueryDTO);
		exportQueryDTO.setType(FILTERCATEGORY);
		String path = AppConfigUtils.getInstance().getConfigPathByTenantId(
				"exportFilePath", "exportFile", appctx.getCurrentTenantId());
		exportQueryDTO.setPath(path);
		
		exportMessageProducer.send(exportQueryDTO);
	}

	/**
	 * 搜索结果导出.
	 */
	@Transactional
	public void exportRequestItems(RequestQueryDTO requestQueryDTO, String sidx, String sord) {
		ExportInfo entity = exportInfoService.saveExportInfoReturnEntity(MODULECATEGORY);
		if(requestQueryDTO!=null){
			requestQueryDTO.setLimit(CSVWriter.EXPORT_SIZE);
			requestQueryDTO.setLoginName(appctx.getCurrentLoginName());
			requestQueryDTO.setCategoryNos(userInfoService.findCategoryNosByLoginName(requestQueryDTO.getLoginName(), "Request_Category_"));// 设置查看权限
			if (StringUtils.hasText(requestQueryDTO.getCurrentUser())) {
				// 查询分类包含的所有子节点
				User user = userDAO.findUniqueBy("loginName", requestQueryDTO.getCurrentUser());
				requestQueryDTO.setOrgNo(user.getOrgnization().getOrgNo());
			}
			// 所属负责的客户
			if (requestQueryDTO.getCompanyNos() == null) {
				requestQueryDTO.setCompanyNos(itsopUserService.findMyAllCustomer(requestQueryDTO.getLastUpdater()));
			}
			requestQueryDTO.setLang(appctx.getCurrentLanguage());
			requestQueryDTO.setExportInfo(entity);
			requestQueryDTO.setSidx(sidx);
			requestQueryDTO.setSord(sord);
			requestQueryDTO.setTenantId(appctx.getCurrentTenantId());
		
			ExportQueryDTO exportQueryDTO=new ExportQueryDTO();
			exportQueryDTO.setTenantId(appctx.getCurrentTenantId());
			exportQueryDTO.setQueryDTO(requestQueryDTO);
			exportQueryDTO.setType(FILTERCATEGORY);
			String path = AppConfigUtils.getInstance().getConfigPathByTenantId(
					"exportFilePath", "exportFile", appctx.getCurrentTenantId());
			exportQueryDTO.setPath(path);
			
			exportMessageProducer.send(exportQueryDTO);
		}
	}

	/**
	 * 转成字符数组
	 * @param request
	 * @param data
	 * @param time
	 * @param money
	 * @param lang
	 */
	private void convertRequestToStringArray(Request request, List<String[]> data, Long time, Double money, String lang) {
		String status = "", category = "",  priority = "", complexity = "",  submitter = "", escalateTo = "", relevantCI = "", assignTeam = "", assignTechnician = "", wTime = "", costMoney = "", serviceDir = "", updateTime = "", solutions = "";
		LanguageContent lc = LanguageContent.getInstance();
		if (request.getStatus() != null) {
			status = request.getStatus().getDname();
		}
		if (request.getEventCategory() != null) {
			category = request.getEventCategory().getEventName();
		}

		if (request.getPriority() != null) {
			priority = request.getPriority().getDname();
		}
		
		if (request.getCreatedBy() != null) {
			submitter = request.getCreatedBy().getFullName();
		}

		if (request.getOwner() != null) {
			escalateTo = request.getOwner().getFullName();
		}
		if (request.getAssigneeGroup() != null) {
			assignTeam = request.getAssigneeGroup().getOrgName();
		}
		if (request.getTechnician() != null) {
			assignTechnician = request.getTechnician().getFullName();
		}
		List<EventCategory> list = request.getServiceDirectory();
		if (list != null && list.size() > 0) {
			for (int i = 0; i < list.size(); i++) {
				EventCategory event = list.get(i);
				serviceDir += event.getEventName() + ",";
			}
			serviceDir = serviceDir.substring(0, serviceDir.length() - 1);
		}
		/*if (time != 0L) {
			Long day = time / 1440;
			time = time - (day * 1440);
			Long hour = time / 60;
			time = time - (hour * 60);
			Long minutes = time;
			wTime = day.toString() + lc.getContent("label.sla.day", lang) + hour.toString() + lc.getContent("label.sla.hour", lang) + minutes.toString() + lc.getContent("label.sla.minute", lang);
		} else
			wTime = 0 + "";
		if (money != null) {
			costMoney = money.toString();
		}*/
		if (request.getLastUpdateTime() != null) {
			updateTime = TimeUtils.format(request.getLastUpdateTime(),TimeUtils.DATETIME_PATTERN);
		}
		if (request.getSolutions() != null && request.getSolutions().length() > 0)
			solutions =StringUtils.stripHtml(request.getSolutions());

		String RequestOrgName = "";
		if (request.getCompanyNo() != null && request.getCompanyNo() != 0l)
			RequestOrgName = organizationDAO.findById(request.getCompanyNo()).getOrgName();
		
		
		try{
			String[] strs=new String[] { 
		            request.getRequestCode(),
		            request.getEtitle(),
		            StringUtils.stripHtml(request.getEdesc()),
		            status,
		            category,
		            serviceDir,
		            RequestOrgName,
		            request.getCreatedBy().getOrgnization().getOrgName(),
		            //receivingWay,
		            priority,
		            //complexity,
		           // influence,
		           // seriousness,
		            submitter,
		            escalateTo,
		           // relevantCI,
		            assignTeam,
		            assignTechnician,
		            formatLongTimeToDateStr(request.getMaxCompleteTime()),
		            formatLongTimeToDateStr(request.getMaxResponseTime()),
		            TimeUtils.format(request.getCreatedOn(),
		            		TimeUtils.DATETIME_PATTERN),
		            TimeUtils.format(request.getResponsesTime(),
		            		TimeUtils.DATETIME_PATTERN), 
		            TimeUtils.format(request.getCloseTime(),
		            		TimeUtils.DATETIME_PATTERN), 
		            updateTime, 
		            getSlaStatusName(request), 
		           // wTime, 
		            //costMoney, 
		            solutions
			};
			Map<Object, Object> map=requestDAO.findByCustom(request.getEno(),true);
			for (Map.Entry<Object, Object> entry : map.entrySet()) {
				//System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
				if(entry.getValue()!=null){
					String val=entry.getValue().toString();
					strs=insert(strs,val.substring(val.indexOf("~")+1));
				}else
					insert(strs,"");
			} 
			data.add(strs);
		}catch (Exception e) {
			e.printStackTrace();
			LOGGER.error(request.getRequestCode()+" Export Data Failure!");
		}
		
	}

	/**
	 * 获取SLA状态
	 * 
	 * @param request
	 * @return
	 */
	private String getSlaStatusName(Request request) {
		String result="";
		String status = getSlaStatus(request);
		DataDictionaryItems datas = dataDictionaryItemsDAO.findUniqueBy("dno", status);
		if (datas != null)
			result=datas.getDname();
		else{
			LOGGER.error("get SlaStatusName is null error");
		}
		return result;	
	}

	/**
	 * 计算成本和工时
	 * @param request
	 */
	@SuppressWarnings("unchecked")
	private void actualCost(Request request) {
		CostDTO dto = new CostDTO();
		dto.setEno(request.getEno());
		dto.setEventType(ModuleUtils.ITSM_REQUEST);
		PageDTO pagedto = costService.findPagerCost(dto, 0, 100000, null, null);
		List<CostDTO> li = pagedto.getData();
		String type = null;
		if (li.size() > 0 && !li.isEmpty()) {
			for (int i = 0; i < li.size(); i++) {
				type = li.get(i).getType();
				if (type != null && type.equals("HANG")) {
					continue;
				} else {
					workTime += li.get(i).getActualTime();
					cost += li.get(i).getTotalFees();
				}
			}
		}

	}

	/**
	 * 长整形转日期字符串
	 * 
	 * @param longTime
	 * @return String
	 */
	private String formatLongTimeToDateStr(Long longTime) {
		String result="";
		if (longTime != null) {
			Calendar offTime = new GregorianCalendar();
			offTime.setTimeInMillis(longTime);
			result= TimeUtils.format(offTime.getTime(),TimeUtils.DATETIME_PATTERN);
		}
		return result;
	}
	

	/**
	 * 判断SLA状态
	 * @param req
	 * @return String
	 */
	public String getSlaStatus(Request req) {
		String slaStatus = null;
		Long currentTime = new Date().getTime();
		if (req.getHang()) {// 是否挂起
			slaStatus = SLAState.Hang_Up.getValue();
		} else if (req.getMaxResponseTime() != null && req.getMaxCompleteTime() != null) {
			// 判断SLA状态
			// 待响应、超时未响应
			// 超时响应和待完成、超时响应和超时未完成、超时响应和超时完成、超时响应和正常完成
			// 正常响应和待完成、正常响应和超时未完成、正常响应和超时完成、正常响应和正常完成
			if (req.getResponsesTime() == null) {// 响应时间为空=待响应
				slaStatus = SLAState.The_Response.getValue();//TO_BE_RESPONDED;// 待响应
				
				if (currentTime > req.getMaxResponseTime()) {// 响应时间=NULL、当前时间>最大响应时间
																// = 超时未响应
					slaStatus =SLAState.Overtime_Is_Not_Responding.getValue();// 超时未响应
					if (new Date().getTime() > req.getMaxCompleteTime()) {
						slaStatus =SLAState.Overtime_Is_Not_Responding.getValue()+"&"+SLAState.Unfinished.getValue(); 
						
					}
				}
			} else if (req.getMaxResponseTime() != null && req.getMaxCompleteTime() != null) {
				slaStatus = getSLAResponseStatus(req.getResponsesTime(), req.getMaxResponseTime()) + "&" + getSLACompleteStatus(req.getCloseTime(), req.getMaxCompleteTime());
			}
		} else {
			slaStatus =SLAState.OTHER.getValue();
		}
		return slaStatus;
	}

	/**
	 * 响应状态
	 * 
	 * @param responsesTime
	 * @param maxResponseTime
	 * @return String
	 */
	private String getSLAResponseStatus(Date responsesTime, Long maxResponseTime) {
		String SLAResponseStatus = null;
		if (responsesTime.getTime() > maxResponseTime) {// 响应时间>计划响应时间
			SLAResponseStatus = SLAState.The_Timeout.getValue();
			} else if (responsesTime.getTime() < maxResponseTime) {// 响应时间<计划响应时间
			SLAResponseStatus = SLAState.Normal_Response.getValue();//RESPONDED_ONTIME;
		}
		return SLAResponseStatus;
	}

	/**
	 * 完成状态
	 * 
	 * @param closeTime
	 * @param maxCompleteTime
	 * @return
	 */
	private String getSLACompleteStatus(Date closeTime, Long maxCompleteTime) {
		String SLACompleteStatus = null ;
		Long currentTime = new Date().getTime();
		if (closeTime == null) {
			if (currentTime < maxCompleteTime)// 关闭时间=NULL，当前时间<计划完成时间
				SLACompleteStatus =SLAState.To_Be_Bcompleted.getValue();
			else if (currentTime > maxCompleteTime)// 关闭时间=NULL，当前时间>计划完成时间
				SLACompleteStatus =SLAState.Unfinished.getValue();
		} else if (closeTime != null) {
			if (closeTime.getTime() < maxCompleteTime)// 关闭时间!=NULL，关闭时间<计划完成时间
				SLACompleteStatus =SLAState.The_Normal_Completion.getValue();//
			else if (closeTime.getTime() > maxCompleteTime) {
				SLACompleteStatus =SLAState.Complete.getValue();
			}
		}
		return SLACompleteStatus;
	}

	/**
	 * 分页全文检索.
	 * @param queryDTO
	 * @param page
	 * @param rows
	 * @return PageDTO
	 */
	@Transactional
	public PageDTO fullSearch(RequestQueryDTO queryDTO, String sidx, String sord) {

		// 构造相关请求的分页对象
		PageDTO requests = new PageDTO();
		fullTextSearch(queryDTO);
		if(queryDTO.getIds()!=null && queryDTO.getIds().length>0)
			requests=findRequestByPage(queryDTO, sidx, sord);
		return requests;
	}

	private void fullTextSearch(RequestQueryDTO queryDTO ) {
		String[] multiFields=new String[]{"title","code","content"};
		Long[] ids=LuenceUtil.getInstance(MODULECATEGORY).search(queryDTO.getAlias(), multiFields);
		queryDTO.setIds(ids);
	}
	/**
	 * 负责客户的数据统计
	 * @param loginName 登录名
	 * @param isAll 是否要把统计结果为0的显示
	 * @return 统计结果
	 */
	public List<CustomerDataCountDTO> requestDataCountByCompanyNo(String loginName, boolean isAll) {
		Long[] companyNos = itsopUserService.getRelatedCompanyByLoginName(loginName);

		RequestQueryDTO qdto = new RequestQueryDTO();
		qdto.setCompanyNos(companyNos);
		qdto.setCategoryNos(userInfoService.findCategoryNosByLoginName(appctx.getCurrentLoginName(), "Request_Category_"));// 设置查看权限
		List<StatResultDTO> statResult = requestDAO.groupStatRequest(qdto);
		List<CustomerDataCountDTO> countsDTO = new ArrayList<CustomerDataCountDTO>();

		List<Long> statCompanyNo = new ArrayList<Long>();
		for (StatResultDTO srDto : statResult) {
			// 公司信息
			if(srDto.getId()!=null && srDto.getId()!=0){
				CustomerDataCountDTO countDTO = new CustomerDataCountDTO();
				countDTO.setOrgNo(srDto.getId());
				countDTO.setOrgName(orgDAO.findById(srDto.getId()).getOrgName());
				// 统计数据
				countDTO.setTotal(srDto.getQuantity().intValue());
				statCompanyNo.add(srDto.getId());
				countsDTO.add(countDTO);
			}
		}
		// 统计结果为0的返回
		if (isAll) {
			for (Long companyNo : companyNos) {
				if (companyNo!=null && companyNo!=0 && !statCompanyNo.contains(companyNo)) {
					CustomerDataCountDTO countDTO = new CustomerDataCountDTO();
					countDTO.setOrgNo(companyNo);
					countDTO.setOrgName(orgDAO.findById(companyNo).getOrgName());
					countDTO.setTotal(0);
					countsDTO.add(countDTO);
				}
			}
		}
		return countsDTO;
	}

	/**
	 * 恢复数据.
	 * 
	 * @param historyDataNos
	 *            Long[]
	 */
	@Transactional
	public void restoreData(Long[] historyDataNos) {
		if (historyDataNos != null && historyDataNos.length > 0) {
			for (Long id : historyDataNos) {
				RequestDTO dto = (RequestDTO) historyDataService.restore(id, "com.wstuo.itsm.request.dto.RequestDTO");// 取得DTO
				Request entity = new Request();
				if (dto.getEtitle() != null) {
					entity.setEtitle(dto.getEtitle());
				}
				if (dto.getEno() != null) {
					entity.setEno(dto.getEno());
				}
				if (dto.getEdesc() != null) {
					entity.setEdesc(dto.getEdesc());
				}
				if (dto.getRequestCode() != null) {
					entity.setRequestCode(dto.getRequestCode());
				}
				if (dto.getCreatedByNo() != null) {// 创建人
					User u = userDAO.findById(dto.getCreatedByNo());
					if (u != null) {
						entity.setCreatedBy(u);
					}
				}
				if (dto.getOwnerNo() != null) {// 负责人
					User u = userDAO.findById(dto.getOwnerNo());
					if (u != null) {
						entity.setOwner(u);
					}
				}

				if (dto.getServicesNo() != null) {// 服务机构

					OrganizationServices os = organizationServicesDAO.findById(dto.getServicesNo());
					if (os != null) {
						entity.setServicesOrg(os);
					}
				}

				if (dto.getStatusNo() != null) {// 请求状态

					DataDictionaryItems di = dataDictionaryItemsDAO.findById(dto.getStatusNo());
					if (di != null) {
						entity.setStatus(di);
					}
				}

				if (dto.getApprovalName() != null) {// 审批人
					entity.setApprovalName(dto.getApprovalName());
				}

				if (dto.getPid() != null) {// 流程编号
					entity.setPid(dto.getPid());
				}

				if (dto.getAssigneeGroupNo() != null) {// 指派组

					Organization org = organizationDAO.findById(dto.getAssigneeGroupNo());
					if (org != null) {
						entity.setAssigneeGroup(org);
					}
				}
				if (dto.getAssigneeNo() != null) {// 指派技术员

					User u = userDAO.findById(dto.getAssigneeNo());
					if (u != null) {
						entity.setTechnician(u);
					}
				}

				if (dto.getPriorityNo() != null) {// 优先级

					DataDictionaryItems di = dataDictionaryItemsDAO.findById(dto.getPriorityNo());
					if (di != null) {
						entity.setPriority(di);
					}
				}
				if (dto.getRelatedConfigureItemNos() != null) {// 关联配置项
					List<CI> cis = new ArrayList<CI>();
					for (Long cid : dto.getRelatedConfigureItemNos()) {
						CI ci = ciDAO.findById(cid);
						cis.add(ci);
					}
					entity.setRelatedConfigureItems(cis);
				}

				if (dto.getRequestCategoryNo() != null) {// 请求分类
					EventCategory ec = eventCategoryDAO.findById(dto.getRequestCategoryNo());
					if (ec != null) {
						entity.setEventCategory(ec);
					}
				}

				if (dto.getCompanyNo() != null) {// 公司信息

					entity.setCompanyNo(dto.getCompanyNo());
				}

				if (dto.getRequestResponseTime() != null) {// 响应时间
					entity.setResponsesTime(dto.getRequestResponseTime());
				}

				if (dto.getMaxResponseTime() != null) {// 响应时间
					entity.setMaxResponseTime(dto.getMaxResponseTime());
				}

				if (dto.getMaxCompleteTime() != null) {
					entity.setMaxCompleteTime(dto.getMaxCompleteTime());
				}

				if (dto.getMaxCompleteTimeBack() != null) {
					entity.setMaxCompleteTimeBack(dto.getMaxCompleteTimeBack());
				}

				if (dto.getRequestResolvedTime() != null) {
					entity.setRequestResolvedTime(dto.getRequestResolvedTime());
				}

				if (dto.getSlaStatusNo() != null) {// SLA状态
					DataDictionaryItems slaStatus = dataDictionaryItemsDAO.findById(dto.getSlaStatusNo());
					entity.setSlaState(slaStatus);
				}

				requestDAO.merge(entity);

			}
			// 删除备份数据.
			historyDataService.deleteHistoryData(historyDataNos);
		}
	}

	/**
	 * 更新请求SLA状态
	 */
	@SuppressWarnings("unchecked")
	@Transactional
	public void updateRequestSLAStatus() {
		PageDTO pageDto = requestDAO.findSLAStatusRequest();
		List<Request> list = pageDto.getData();
		for (Request request : list) {
			String slaStatus = getSlaStatus(request);
			DataDictionaryItems dic = dataDictionaryItemsDAO.findUniqueBy("dno", slaStatus);
			if (request.getSlaState() == null&&dic!=null) {
				request.setSlaState(dic);
			} else if (!request.getSlaState().getDname().equals(slaStatus)&&dic!=null) {
				request.setSlaState(dic);
			}
		}
	}
	/**
	 * 重新匹配SLA.
	 * @param fitType
	 * @param requestId
	 * @param slaNo
	 */
	@Transactional
	public void reFitSLA(String fitType, Long requestId, Long slaNo, HistoryRecordDTO his) {
		Request request = requestDAO.findById(requestId);
		RequestDTO dto = new RequestDTO();
		if (SLAFITTYPE_MANUAL_SIGN.equals(fitType)) {// 手动的
			dto.setSlaNo(slaNo);
		} else {// 通过规则去匹配
			entity2dto(request, dto);
			// 请求规则匹配
			requestRuleMatch(dto);
			// 获取SLA
			dto = getRequestFitSlaRule(dto);
		}
		// 计算SLA响应完成时间
		dto.setCreatedOn(request.getCreatedOn());
		calcRequestSLATime(dto);
		request = setSla(dto, request);
		if (his != null) {
			his.setLogDetails(his.getLogDetails() + dto.getMatchRuleName());
			// 保存历史记录
			saveHistoryRecord(request.getEno(), his);
		}
		

	}

	/**
	 * 导入请求业务数据
	 */
	@Transactional
	public String importRequest(File importFile) {
		try {
			String fileEncode = FileEncodeUtils.getFileEncode(importFile);
			Reader rd = new InputStreamReader(new FileInputStream(importFile), fileEncode);// 以字节流方式读取数据
			CSVReader reader = new CSVReader(rd);
			String[] line = null;
			try {

				while ((line = reader.readNext()) != null) {
					RequestDTO request = new RequestDTO();
					// 申请 人
					request.setCreatedByName("admin");
					request.setCreator("admin");
					// 标题
					request.setEtitle(line[0].toString());
					// 内容
					request.setEdesc(line[1].toString());
					// 事件分类
					// request.setRequestCategoryNo(Long.parseLong(line[2].toString()));
					if (line[2] != null) {
						List<EventCategory> gory = eventCategoryDAO.findBy("eventName", line[2].toString());
						if (gory != null) {
							request.setRequestCategoryNo(gory.get(0).getEventId());// 事件分类
						}
					}
					// 优先级
					if (line[3] != null) {
						List<DataDictionaryItems> lis = dataDictionaryItemsDAO.findItemByGroupCodeAndName("priority", line[3].toString());
						if (lis != null) {
							request.setPriorityNo(lis.get(0).getDcode());
						}
					}
					// 影响度
					if (line[4] != null) {
						List<DataDictionaryItems> lis = dataDictionaryItemsDAO.findItemByGroupCodeAndName("effectRange", line[4].toString());
						if (lis != null) {
							request.setEffectRangeNo(lis.get(0).getDcode());
						}
					}
					if (line[5] != null) {
						List<DataDictionaryItems> lis = dataDictionaryItemsDAO.findItemByGroupCodeAndName("seriousness", line[5].toString());
						if (lis != null) {
							request.setSeriousnessNo(lis.get(0).getDcode());
						}
					}
					if (line[6] != null) {
						List<DataDictionaryItems> lis = dataDictionaryItemsDAO.findItemByGroupCodeAndName("level", line[6].toString());
						if (lis != null) {
							request.setLevelNo(lis.get(0).getDcode());
						}
					}
					// 来源方式
					if (line[7] != null) {
						List<DataDictionaryItems> lis = dataDictionaryItemsDAO.findItemByGroupCodeAndName("imode", line[7].toString());
						if (lis != null) {
							request.setImodeNo(lis.get(0).getDcode());
						}
					}
					// 所属客户
					request.setCompanyNo((long) 1);
					request.getPiv().put("approvalNo", 0);
					saveRequest(request);
				}

			} catch (IOException e) {
				LOGGER.error(e);
			} catch (ApplicationException ex) {
				LOGGER.error(ex);
			}

		} catch (Exception e1) {
			LOGGER.error(e1);
		}
        return "";
	}

	//判断是否是IP
	@SuppressWarnings("unused")
	private boolean isIP(String addr){
      if(addr.length() < 7 || addr.length() > 15 || !StringUtils.hasText(addr)){
        return false;
      }
      //判断IP格式和范围
      String rexp = "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$";
      Pattern pat = Pattern.compile(rexp);  
      Matcher mat = pat.matcher(addr);  
      boolean ipAddress = mat.find();
      return ipAddress;
    }
	
	//获取IP
	@SuppressWarnings("unused")
	private String getIP(String addr){
		String ip = "";
		String regexString="(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})";
		Pattern p = Pattern.compile(regexString);
		Matcher m = p.matcher(addr);
		while (m.find()) {
			 ip =m.group();
		}
		return ip;
    }
	
	/**
	 * 监控软件HTTP集成创建请求(第三方)
	 * @param phoneNumber
	 * @param message
	 * @param loginName
	 * @param password
	 * @return String
	 */
	@Transactional
	public String createRequest(RequestHttpDTO httpDto) {
		String result="";
		String title = httpDto.getMessage() ;
		// 用户验证
		User authUser = userDAO.findUserByLoginNameAndPwd(httpDto.getLoginName(), httpDto.getPassword());
		if (authUser == null) {
			result= "UserName Password Authentication Failure";
		} else {
			// 通过手机号码获取用户
			UserQueryDTO qdto = new UserQueryDTO();
			qdto.setMobilePhone(httpDto.getPhoneNumber());
			// 根据手机号码获取所有用户
			List<User> users = userDAO.findUserByNumber(qdto);
			// 构建请求DTO
			RequestDTO requestDTO = new RequestDTO();
			//操作者
			requestDTO.setCreator(httpDto.getLoginName());
			// 所属公司(默认为当前公司)
			requestDTO.setCompanyNo(1L);
			// 标题
			requestDTO.setEtitle(title);
			// 描述
			requestDTO.setEdesc(title);
			// 请求人(使用验证的用户做为请求人)
			requestDTO.setCreatedByNo(authUser.getUserId());
			// 指派技术员
			if (users != null && users.size() > 0)
				requestDTO.setAssigneeNo(users.get(0).getUserId());
			this.saveRequest(requestDTO);
			result= "Success";
		}
		return result;
	}
	/**
	 * 请求响应
	 * @param request
	 */
	private void requestResponse(Request request,String operator){
		if (request.getResponsesTime() == null) {
			request.setResponsesTime(new Date());
			// 更新SLA状态(Tan)
			String slaStatus = getSlaStatus(request);
			request.setSlaState(dataDictionaryItemsDAO.findUniqueBy("dno", slaStatus));
			// 对应的通知规则
			requestProcessNotice(INoticeRuleService.REQUEST_RESPONSES_NOTIC, request, null, null, null, operator, null, null);
		}
	}
	/**
	 * 发布任务指派
	 */
	@Transactional
	public void assignTask(ProcessHandleDTO dto){
		Request request = requestDAO.findById(dto.getEno());
		// 请求响应
		requestResponse(request,dto.getOperator());
		String pid = request.getPid();
		RequestDTO requestDTO = new RequestDTO();
		entity2dto(request, requestDTO);
		requestDTO.setEdesc(null);//描述不用放入流程变量
		bpi.setInstanceVariables(pid, requestDTO);
		//任务指派
		Object bean = bpi.assignTask(dto, requestDTO);
		//更新指派
		updateAssign(request,bean);
	}
	
	/**
	 * 流程处理
	 * @param phDTO
	 */
	@Transactional
	public void processHandle(ProcessHandleDTO phDTO) {
		Request request = requestDAO.findById(phDTO.getEno());
		Long eventId = null;
		if( request.getRequestCategory()!=null){
			eventId = request.getRequestCategory().getEventId();
		}
		String tgId = "";
		if(request.getAssigneeGroup()!=null){
			tgId = request.getAssigneeGroup().getOrgNo().toString();
		}
		final String belongsGroupIds = tgId;
		final Long categoryId = eventId;
		class AssignByBusy implements ICustomAssign{
			public Object execute(){
				return automaticallyAssignedByBusy(categoryId,belongsGroupIds,null);
			}
		}
		// 请求响应
		requestResponse(request,phDTO.getOperator());
		
		String pid = request.getPid();
		
		RequestDTO requestDTO = new RequestDTO();
		entity2dto(request, requestDTO);
		// 任务完成并流转
		bpi.completeTask(phDTO.getOperator(), phDTO.getTaskId(), phDTO.getOutcome());
		//任务指派
		Object bean = bpi.assignTask(phDTO, requestDTO, new AssignByBusy());
		//更新指派
		updateAssign(request,bean);
		
		// 判断流程实例是否已结束
		boolean result = bpi.isEnded(pid);

		// 判断流程实例是否已结束
		if (result) {
			requestClose(request, phDTO);
		}else{
			// 修改请求状态
			updateRequestStatus(phDTO.getEno(), phDTO.getPid());
		}
		// 修改请求
		phDTO.setPid(request.getPid());
		phDTO.setEno(request.getEno());
		requestDAO.merge(request);
	}

	/**
	 * 指派更新
	 * @param request
	 * @param bean
	 */
	private void updateAssign(Request request,Object bean){
		if(bpi.isUpdateEventAssign(request.getPid())){
			try {
				String technicianNo = BeanUtils.getProperty(bean, "taskAssigneeNo");
				if(StringUtils.hasText(technicianNo)){
					User technician = userDAO.findById(Long.parseLong(technicianNo));
					request.setTechnician(technician);
				}
			} catch (IllegalAccessException e) {
				LOGGER.error("Get propery taskAssigneeNo error "+e.getMessage());
			} catch (InvocationTargetException e) {
				LOGGER.error("Get propery taskAssigneeNo error "+e.getMessage());
			} catch (NoSuchMethodException e) {
				LOGGER.error("Get propery taskAssigneeNo error "+e.getMessage());
			}
			try {
				String assigneeGroupNo = BeanUtils.getProperty(bean, "taskassigneeGroupNo");
				if(StringUtils.hasText(assigneeGroupNo)){
					Organization org = orgDAO.findById(Long.parseLong(assigneeGroupNo));
					request.setAssigneeGroup(org);
				}
			} catch (IllegalAccessException e) {
				LOGGER.error("Get propery taskassigneeGroupNo error "+e.getMessage());
			} catch (InvocationTargetException e) {
				LOGGER.error("Get propery taskassigneeGroupNo error "+e.getMessage());
			} catch (NoSuchMethodException e) {
				LOGGER.error("Get propery taskassigneeGroupNo error "+e.getMessage());
			}
		}
		//根据流程规则更新请求
		updateRequestByProcessRule(request, bean);
	}
	/**
	 * 根据流程规则更新请求
	 * @param request
	 * @param bean
	 */
	private void updateRequestByProcessRule(Request request,Object bean){
		try {
			//服务机构
			String servicesNo = BeanUtils.getProperty(bean , "servicesNo");
			if(StringUtils.hasText(servicesNo)){
				request.setServicesOrg(organizationServicesDAO.findById(Long.parseLong(servicesNo)));
			}
		} catch (IllegalAccessException e) {
			LOGGER.error("Get propery servicesNo error "+e.getMessage());
		} catch (InvocationTargetException e) {
			LOGGER.error("Get propery servicesNo error "+e.getMessage());
		} catch (NoSuchMethodException e) {
			LOGGER.error("Get propery servicesNo error "+e.getMessage());
		}
		
		try {
			//负责人
			String updateLevelNo = BeanUtils.getProperty(bean , "updateLevelNo");
			if(StringUtils.hasText(updateLevelNo)){
				User ul = userDAO.findById(Long.parseLong(updateLevelNo));
				request.setOwner(ul);
			}
		} catch (IllegalAccessException e) {
			LOGGER.error("Get propery updateLevelNo error "+e.getMessage());
		} catch (InvocationTargetException e) {
			LOGGER.error("Get propery updateLevelNo error "+e.getMessage());
		} catch (NoSuchMethodException e) {
			LOGGER.error("Get propery updateLevelNo error "+e.getMessage());
		}
		try {
			//影响范围
			String effectRangeNo = BeanUtils.getProperty(bean , "effectRangeNo");
			if(StringUtils.hasText(effectRangeNo)){
				request.setEffectRange(dataDictionaryItemsDAO.findById(Long.parseLong(effectRangeNo)));
			}
		} catch (IllegalAccessException e) {
			LOGGER.error("Get propery effectRangeNo error "+e.getMessage());
		} catch (InvocationTargetException e) {
			LOGGER.error("Get propery effectRangeNo error "+e.getMessage());
		} catch (NoSuchMethodException e) {
			LOGGER.error("Get propery effectRangeNo error "+e.getMessage());
		}
		try {
			//紧急度
			String seriousnessNo = BeanUtils.getProperty(bean , "seriousnessNo");
			if(StringUtils.hasText(seriousnessNo)){
				request.setSeriousness(dataDictionaryItemsDAO.findById(Long.parseLong(seriousnessNo)));
			}
		} catch (IllegalAccessException e) {
			LOGGER.error("Get propery seriousnessNo error "+e.getMessage());
		} catch (InvocationTargetException e) {
			LOGGER.error("Get propery seriousnessNo error "+e.getMessage());
		} catch (NoSuchMethodException e) {
			LOGGER.error("Get propery seriousnessNo error "+e.getMessage());
		}
		try {
			//优先级
			String priorityNo = BeanUtils.getProperty(bean , "priorityNo");
			if(StringUtils.hasText(priorityNo)){
				request.setPriority(dataDictionaryItemsDAO.findById(Long.parseLong(priorityNo)));
			}
		} catch (IllegalAccessException e) {
			LOGGER.error("Get propery priorityNo error "+e.getMessage());
		} catch (InvocationTargetException e) {
			LOGGER.error("Get propery priorityNo error "+e.getMessage());
		} catch (NoSuchMethodException e) {
			LOGGER.error("Get propery priorityNo error "+e.getMessage());
		}
		
		try {
			// 请求分类
			String requestCategoryNo = BeanUtils.getProperty(bean , "requestCategoryNo");
			if(StringUtils.hasText(requestCategoryNo)){
				EventCategory eventCategory = eventCategoryDAO.findById(Long.parseLong(requestCategoryNo));
				if (eventCategory != null) {
					request.setRequestCategory(eventCategory);
					request.setEventCategory(eventCategory);
					// 如果请求分类不为空，则使用分类定义的规则编码
					if(StringUtils.hasText(eventCategory.getCategoryCodeRule())){
						String eventCode = request.getRequestCode();// 旧的请求编码
						eventCode = eventCode.replaceAll(eventCode.substring(0, eventCode.lastIndexOf("-")), eventCategory.getCategoryCodeRule());// 更新请求编码
						request.setRequestCode(eventCode);// 赋值于分类规则
					}
				}
			}
		} catch (IllegalAccessException e) {
			LOGGER.error("Get propery requestCategoryNo error "+e.getMessage());
		} catch (InvocationTargetException e) {
			LOGGER.error("Get propery requestCategoryNo error "+e.getMessage());
		} catch (NoSuchMethodException e) {
			LOGGER.error("Get propery requestCategoryNo error "+e.getMessage());
		}
	}
	/**
	 * 实体转DTO
	 * @param req
	 * @param dto
	 */
	@Transactional
	public void entity2dto(Request req, RequestDTO dto) {
		RequestDTO.entity2dto(req, dto);
		dto.setEventType(ModuleUtils.ITSM_REQUEST);
		User createdUser = req.getCreatedBy();
		// 最大响应时间、最大完成时间
		if (req.getMaxResponseTime() != null) {
			dto.setMaxResponsesTime(TimeUtils.formatLongTimeToDate(req.getMaxResponseTime()));
		}
		if (req.getMaxCompleteTime() != null) {
			dto.setMaxCompletesTime(TimeUtils.formatLongTimeToDate(req.getMaxCompleteTime()));
		}
		if(req.getStatus()!=null){
			dto.setStatusName(req.getStatus().getDname());
		}
		//请求编号
		if(StringUtils.hasText(req.getRequestCode())){
			dto.setEcode(req.getRequestCode());
		}
		if (createdUser != null) {
			dto.setCreatedByName(createdUser.getFullName());
			dto.setCreatedByNo(createdUser.getUserId());
			if(createdUser.getOrgnization()!=null){
				dto.setOrganizationNo(createdUser.getOrgnization().getOrgNo());
			}
			dto.setCompanyNo(createdUser.getCompanyNo());
			dto.setCreatedByPhone(createdUser.getPhone());
		}
		if (req.getPriority() != null) {// 优先级
			dto.setPriorityName(req.getPriority().getDname());
			dto.setPriorityNo(req.getPriority().getDcode());
		}
		if (req.getEffectRange() != null) {// 影响范围
			dto.setEffectRangeName(req.getEffectRange().getDname());
			dto.setEffectRangeNo(req.getEffectRange().getDcode());
		}
		if (req.getSeriousness() != null) {// 紧急度
			dto.setSeriousnessName(req.getSeriousness().getDname());
			dto.setSeriousnessNo(req.getSeriousness().getDcode());
		}
		if (req.getLevel() != null) {// 级别
			dto.setLevelNo(req.getLevel().getDcode());
			dto.setComplexity(req.getLevel().getDname());
		}
		if (req.getRequestCategory() != null) {// 请求分类
			dto.setRequestCategoryName(req.getRequestCategory().getEventName());
			dto.setRequestCategoryNo(req.getRequestCategory().getEventId());
			dto.setEcategoryName(req.getRequestCategory().getEventName());
		}
		if (req.getImode() != null) {// 来源
			dto.setImodeNo(req.getImode().getDcode());
			dto.setImodeName(req.getImode().getDname());
		}
		List<EventCategory> sds = req.getServiceDirectory();
		if (sds != null && sds.size() > 0) {
			Long[] sdsNo = new Long[sds.size()];
			int i = 0;
			for (EventCategory ec : sds) {
				if(ec!=null){
					sdsNo[i] = ec.getEventId();
					i++;
				}
			}
			dto.setServiceDirIds(sdsNo);
		}
		if (req.getRelatedConfigureItems() != null) {
			StringBuffer ciname = new StringBuffer();
			Set<Long>  cicategoryNos = new HashSet<Long>();
			for (CI ci : req.getRelatedConfigureItems()) {
				ciname.append(ci.getCiname()+",");
				cicategoryNos.add(ci.getCategory().getCno());
			}
			if(ciname.length()>0){
				dto.setCiname(ciname.substring(0, ciname.length()-1).toString());
			}
			dto.setCicategoryNos((Long[]) cicategoryNos.toArray(new Long[cicategoryNos.size()]));
		}
		dto.setWeekNo(TimeUtils.getWeekOfDate(new Date()));
		//指派组
		Organization org = req.getAssigneeGroup();
		if (req.getAssigneeGroup() != null) {
			dto.setAssigneeGroupName(org.getOrgName());
			dto.setAssigneeGroupNo(org.getOrgNo());
		}
		//指派技术员
		User technician = req.getTechnician();
		if(technician!= null){
			dto.setTechnicianNo(technician.getUserId());
			dto.setTechnicianName(technician.getFullName());
		}
		EventCategory location=req.getLocation();
		if(location!=null){
			dto.setLocationNos(location.getEventId());
			dto.setLocationName(location.getEventName());
		}
		if(req.getEno()!=null){
			dto.setEno(req.getEno());
			//历史记录
			HistoryRecordDTO historyRecordDTO = new HistoryRecordDTO();
			historyRecordDTO.setEno(req.getEno());
			historyRecordDTO.setEventType(ModuleUtils.ITSM_REQUEST);
			List<HistoryRecordDTO> historyRecordsDTO = historyRecordService.findAllHistoryRecord(historyRecordDTO);
			dto.setHistoryRecordDTO(historyRecordsDTO);
			//visitId  
			if(userReturnVisitDAO.findBy("eno",req.getEno())!=null&&userReturnVisitDAO.findBy("eno",req.getEno()).size()>0)
			dto.setVisitId(userReturnVisitDAO.findBy("eno",req.getEno()).get(0).getVisitId());
		}
	}

	/**
	 * 流程处理的邮件通知
	 * @param request
	 * @param noticeRuleId
	 */
	@SuppressWarnings("unused")
	@Deprecated
	private void processHandleNotice(Request request, Long noticeRuleId, String activityName, String outcome, String operator) {
		if (noticeRuleId != null) {
			RequestDTO dto = new RequestDTO();
			entity2dto(request, dto);
			// 对应的通知规则
			NoticeInfoDTO noticeInfoDto = new NoticeInfoDTO();
			noticeInfoDto.setNoticeRuleId(noticeRuleId);
			dto.setOutcome(outcome);
			dto.setActivityName(activityName);
			dto.setOperator(operator);//设置操作人 
			noticeInfoDto.setVariables(dto);//设置邮件通知模板变量
			// 技术员
			noticeInfoDto.setAssignTechnician(request.getTechnician());
			// 指派机构
			noticeInfoDto.setAssignOrg(request.getAssigneeGroup());
			// 请求人
			noticeInfoDto.setRequester(request.getCreatedBy());
			// 升级到或负责人
			noticeInfoDto.setOwner(request.getOwner());
			noticeRuleService.commonNotice(noticeInfoDto);
		}
	}
	/**
	 * 是否是一线工程师角色
	 * @param technician
	 * @return 是否是一线工程师角色结果
	 */
	private boolean isHelpdeskRoleUser(User technician){
		boolean result = false;
		if(technician!=null){
			Set<Role> roles = technician.getRoles();
			for(Role role : roles){
				if("ROLE_HELPDESKENGINEER".equals(role.getRoleCode())){
					result = true;
					break;
				}
			}
		}
		return result;
	}
	/**
	 * 请求关闭
	 * @param request
	 * @param processHandleDto
	 */
	private void requestClose(Request request, ProcessHandleDTO processHandleDto) {
		//如果指派的技术员是Helpdesk角色用户，则为一线解决
		User technician = request.getTechnician();
		if(isHelpdeskRoleUser(technician)){
			request.setIsFCR(true);
		}
		if (request.getCloseTime() == null) {
			request.setCloseTime(new Date());
		}
		SLARule slaRule = request.getSlaRule();
		Long ServicesNo = slaRule.getSlaContract().getServiceOrg().getOrgNo();
		List<Holiday> holidays = holidayDAO.findHolidayByServicesNo(ServicesNo);
		ServiceTime serviceTime = serviceTimeDAO.findByOrgNo(ServicesNo);
		List<Date> affdays = calcPredictTimeUtils.mergeHoliday(request.getResponsesTime().getTime(), serviceTime, holidays);
		Long handleTimeLong = calcPredictTimeUtils.calcPendingTimeLong(request.getResponsesTime(), request.getCloseTime(), serviceTime, affdays);
		request.setHandleTimeLong(handleTimeLong);
		request.setCloseCode(processHandleDto.getOutcome());
		// 请求关闭后，把升级等标识的去掉
		request.setUpgradeApplySign(null);
		// 请求状态：已关闭
		request.setStatus(dataDictionaryItemsDAO.findUniqueBy("dno", "request_close"));

		// 请求关闭通知
		requestProcessNotice(INoticeRuleService.REQUEST_CLOSE_NOTICE, request, null, null, null, null, processHandleDto.getEmailAddress(), processHandleDto.getOutcome());

		if (request.getStatus() == null)
			throw new ApplicationException("ERROR_REQUEST_STATUS_IS_NULL");
		// SLA状态
		String slaStatus = getSlaStatus(request);
		request.setSlaState(dataDictionaryItemsDAO.findUniqueBy("dno", slaStatus));
		// 发送请求工单
		requestProcessNotice(INoticeRuleService.REQUEST_SEND_REQUES_TORDER, request, null, null, null, null,  processHandleDto.getEmailAddress(), null);
	}

	/**
	 * 根据流程实例ID，去更新指定活动下的对应状态
	 * 
	 * @param eno
	 * @param pid
	 */
	@Transactional
	public void updateRequestStatus(Long eno, String pid) {
		Request request = requestDAO.findById(eno);
		// 根据流程实例ID获取当前活动名称
		String activityName = bpi.getActivityNameByPid(pid);
		if (StringUtils.hasText(activityName)) {
			String pdId = bpi.getProcessDefinitionIdByPid(pid);
			FlowActivityDTO flowActivityDTO = flowPropertyService.findFlowActivity(pdId, new String[] { FlowActivityDTO.TaskActivityType }, activityName);
			if (flowActivityDTO.getStatusNo() != null) {
				request.setStatus(dataDictionaryItemsDAO.findById(flowActivityDTO.getStatusNo()));
			}
		}
	}

	/**
	 * 保存服务目录
	 * 
	 * @param requestDetailDTO
	 * @param serviceDirectory
	 */
	@Transactional
	public void saveServiceDirectory(RequestDetailDTO requestDetailDTO, Long[] serviceDirectory) {
		Request request = requestDAO.findById(requestDetailDTO.getEno());
		if(request!=null){
			request.setServiceDirectory(findCategoryArray(serviceDirectory));
			requestDAO.merge(request);
		}
	}

	/**
	 * 递归查找子分类.数组
	 * 
	 * @param eventId
	 * @return List<EventCategory>
	 */
	@Transactional
	private List<EventCategory> findCategoryArray(Long[] eventId) {
		List<EventCategory> categoryArray = new ArrayList<EventCategory>();

		for (int k = 0; k < eventId.length; k++) {
			EventCategory entity = eventCategoryDAO.findById(eventId[k]);
			if(entity!=null)
				// 递归
				cycleSubCategory(entity, categoryArray);
		}
		return categoryArray;
	}

	/**
	 * 移除服务目录
	 * 
	 * @param requestDetailDTO
	 * @param serviceDirectoryId
	 */
	@Transactional
	public void removeServiceDirectory(RequestDetailDTO requestDetailDTO, Long serviceDirectoryId) {
		Request request = requestDAO.findById(requestDetailDTO.getEno());
		if(request!=null){
			List<EventCategory> serviceDirectorys = request.getServiceDirectory();
			for (EventCategory eventCategory : serviceDirectorys) {
				if (eventCategory.getEventId().equals(serviceDirectoryId)) {
					serviceDirectorys.remove(eventCategory);
					request.setServiceDirectory(serviceDirectorys);
					requestDAO.merge(request);
					return;
				}
			}
		}
	}

	/**
	 * 查询服务目录
	 * 
	 * @param requestQueryDTO
	 * @return List<EventCategoryDTO>
	 */
	@Transactional
	public List<EventCategoryDTO> findSolutionByRequestId(RequestQueryDTO requestQueryDTO) {
		List<EventCategoryDTO> solutions = new ArrayList<EventCategoryDTO>();
		Request request = requestDAO.findById(requestQueryDTO.getEno());
		// 递归
		List<EventCategory> eventCategoryList = new ArrayList<EventCategory>();
		eventCategoryList = request.getServiceDirectory();
		if (eventCategoryList != null && eventCategoryList.size() > 0) {
			for (EventCategory ct : eventCategoryList) {
				EventCategoryDTO dto = new EventCategoryDTO();
				dto.setEventId(ct.getEventId());
				dto.setEventName(ct.getEventName());
				dto.setScores(ct.getScores());
				solutions.add(dto);
			}
		}

		return solutions;
	}

	/**
	 * 递归读取子分类
	 * 
	 * @param entity
	 * @param eventCategoryList
	 */

	private void cycleSubCategory(EventCategory entity, List<EventCategory> eventCategoryList) {

		if (entity != null && entity.getDataFlag() != 99) {
			try {
				eventCategoryList.add(entity);

				if (!entity.getParentChildren().isEmpty()) {
					for (EventCategory ecy : entity.getParentChildren()) {
						cycleSubCategory(ecy, eventCategoryList);
					}
				}
			} catch (Exception ex) {
				throw new ApplicationException("Exception caused while converting Entity into DTO: " + ex.getMessage(), ex);
			}

		}
	}
	/**
	 * 报表可链接查询返回值处理
	 * return pageDTO 转换好的数据
	 */
	@SuppressWarnings("unchecked")
	@Transactional
	public PageDTO findRequestsByCrosstabCell(KeyTransferDTO ktd, int start, int rows, String sidx, String sord) {
		// 负责的所属客户
		Long[] companyNos = itsopUserService.findMyAllCustomer(appctx.getCurrentLoginName());
		ktd.setEntityClass(ENTITYCLASS);
		ktd.setFilterCategory(FILTERCATEGORY);
		PageDTO pageDTO = linksEventQueryServices.finddynamic(ktd, companyNos, start, rows, sidx, sord);
		List<Request> entities = pageDTO.getData();
		List<RequestGridDTO> dtos = new ArrayList<RequestGridDTO>();
		for (Request req : entities) {
			RequestGridDTO dto = new RequestGridDTO();
			entity2GridDto(req, dto);
			dtos.add(dto);
		}
		pageDTO.setData(dtos);
		return pageDTO;
	}

	/**
	 * 请求动作通知规则
	 * 
	 * @param noticeRuleNo
	 *            通知规则编号
	 * @param request
	 *            请求实体
	 * @param loginNames
	 *            登录名
	 * @param users
	 *            用户
	 */
	@Transactional
	public void requestProcessNotice(String noticeRuleNo, Request request, List<String> loginNames, List<User> users, String visitPath, String operator, String emailAddress, String outCome) {
		RequestDTO dto = new RequestDTO();
		entity2dto(request, dto);
		dto.setVisitPath(visitPath);
		NoticeInfoDTO noticeInfoDto = new NoticeInfoDTO();
		noticeInfoDto.setEmailAddress(emailAddress);
		noticeInfoDto.setNoticeRuleNo(noticeRuleNo);
		noticeInfoDto.setLoginName(loginNames);
		dto.setOperator(operator);//处理人
		noticeInfoDto.setVariables(dto);
		noticeInfoDto.setCompanyNo(request.getEno());// 用此字段保存事件编号
		noticeInfoDto.setCompanyName(FILTERCATEGORY);// 用此字段保存事件类型
		User technician = request.getTechnician();
		if (technician != null) {
			noticeInfoDto.setUserNo(technician.getUserId());
			// 技术员
			noticeInfoDto.setAssignTechnician(technician);
		}
		if (technician != null && technician.getUserId() != 0) {
			noticeInfoDto.setUserNo(request.getCreatedBy().getUserId());
		}
		if (request.getAssigneeGroup() != null) {
			noticeInfoDto.setOrgNo(request.getAssigneeGroup().getOrgNo());
			// 指派机构
			noticeInfoDto.setAssignOrg(request.getAssigneeGroup());
		}
		if (users != null) {
			noticeInfoDto.setNoticeUsers(users);
		}
		if (request.getCreatedBy() != null) {
			// 请求人
			noticeInfoDto.setRequester(request.getCreatedBy());
		}
		if (request.getOwner() != null) {
			noticeInfoDto.setOwner(request.getOwner());
		}
		noticeRuleService.commonNotice(noticeInfoDto);
	}

	/**
	 * 查找解决方案附件
	 * 
	 * @param eno
	 * @return CommentDTO
	 */
	@Transactional
	public CommentDTO findCommentDTOByEno(Long eno) {
		Request entity = requestDAO.findById(eno);
		CommentDTO cmdto = null;
		if (entity.getRequestSolutions() != null) {
			cmdto = new CommentDTO();
			if (entity.getRequestSolutions().getAttachments() != null && entity.getRequestSolutions().getAttachments().size() > 0) {
				cmdto.setAttachments(entity.getRequestSolutions().getAttachments());
			}
		}
		return cmdto;
	}

	/**
	 * 删除解决方案附件
	 * 
	 * @param eno
	 * @param aid
	 */
	@Transactional
	public void deleteAttachment(Long eno, Long aid) {
		Request req = requestDAO.findById(eno);
		Attachment attr = attachmentService.findAttachmentById(aid);
		req.getRequestSolutions().getAttachments().remove(attr);
		requestDAO.save(req);
	}

	/**
	 * 根据繁忙程度自动指派技术员
	 * @return User
	 */
	@SuppressWarnings("unchecked")
	public User automaticallyAssignedByBusy(Long categoryId,String belongsGroupIds,List<String> userName) {
		List<Object[]> list = requestDAO.findUserRequestStats(categoryId,belongsGroupIds, userName);
		User user =null;
		if(list.size() > 0 ){
			Object[] obj = list.get(0);
			String loginName = obj[0].toString();
    		user = userDAO.findUniqueBy("loginName", loginName);
	    }
		return user;
	}
	/**
	 * 技术员繁忙程度统计
	 * 
	 * @param page
	 * @param rows
	 * @return PageDTO
	 */
	@SuppressWarnings("unchecked")
	@Transactional
	public PageDTO workloadStatusStatistics(int page, int rows, String sidx, String sord) {
		int start = (page -1) * rows;
		Long[] companyNos = itsopUserService.findMyAllCustomer(appctx.getCurrentLoginName());
		PageDTO p = requestDAO.findUserRequestStatsBySort(companyNos,sidx, sord, start, rows);
		List<Object[]> list = p.getData();
		List<AutomaticallyAssignedDTO> autos = setAutomaticallyAssignedListDTO(list);
		p.setData(autos);
		p.setTotalSize(userDAO.countUserByTechnician());
		return p;
	}
	/**
	 * set AutomaticallyAssigned ListDTO And Sort
	 * @param list
	 * @param sidx
	 * @param sord
	 * @return List<AutomaticallyAssignedDTO> 
	 */
	private List<AutomaticallyAssignedDTO> setAutomaticallyAssignedListDTO(List<Object[]> list){
		List<AutomaticallyAssignedDTO> autos = new ArrayList<AutomaticallyAssignedDTO>();
		for (Object[] obj : list) {
			AutomaticallyAssignedDTO auto = new AutomaticallyAssignedDTO();
			String loginName =obj[0]!=null?obj[0].toString():"";
			auto.setLoginName(loginName);
			auto.setFullName(obj[1]!=null?obj[1].toString():"");
			auto.setCountAssignedMineRquest(obj[2]!=null?Long.parseLong(obj[2].toString()):0L);
			auto.setCountMineHandingRequest(obj[3]!=null?Long.parseLong(obj[3].toString()):0L);
			auto.setCountMineNewRequest(obj[4]!=null?Long.parseLong(obj[4].toString()):0L);
			auto.setServicesTotalScore(obj[5]!=null?Long.parseLong(obj[5].toString()):0L);
			autos.add(auto);
		}
		return autos;
	}

	/**
	 * 转换模板值
	 * 
	 * @param requestDTO
	 * @param cinos
	 * @return RequestDTO
	 */
	@Transactional
	public RequestDTO convertRequestTemplateValue(RequestDTO requestDTO, Long[] cinos) {
		if (requestDTO.getServiceDirIds() != null && requestDTO.getServiceDirIds().length > 0) {
			Map<Long, String> map = new HashMap<Long, String>();
			Map<Long, Long> map2 = new HashMap<Long, Long>();
			for (Long sNo : requestDTO.getServiceDirIds()) {
				if(sNo!=null){
					EventCategory ss = eventCategoryDAO.findById(sNo);
					if(ss!=null){
						map.put(ss.getEventId(), ss.getEventName());
						map2.put(ss.getEventId(), (long) ss.getScores());
					}
				}
			}
			requestDTO.setServiceNos(map);
			requestDTO.setScores(map2);
		}
		List<Long> ids = new ArrayList<Long>();
		if (cinos != null) {
			for (int i = 0; i < cinos.length; i++) {
				ids.add(cinos[i]);
			}
		}
		requestDTO.setRelatedCiNos(ids);
		return requestDTO;
	}
	   /**
	    * 创建请求的消费方法
	    * @param dto
	    */
	public void saveRequestConsumer(RequestDTO dto){
		boolean bl = true;
		if(dto != null){
			User temp = new User();
			temp.setLoginName(dto.getCreatedByName());
			temp.setPassword(dto.getCreator());//密码是临时存放在dto的creator属性中的
			if ( userInfoService.userLogin(temp.getLoginName(), temp.getPassword()) ) {//验证账户
				bl = false;
				//影响范围
				if (dto.getEffectRangeName() != null) {
					dto.setEffectRangeNo(getDicItemNo("effectRange", dto.getEffectRangeName()));
				}
				//紧急度
				if (dto.getSeriousnessName() != null) {
					dto.setSeriousnessNo(getDicItemNo("seriousness", dto.getSeriousnessName()));
				}
				//优先级
				if (dto.getPriorityName() != null) {
					dto.setPriorityNo(getDicItemNo("priority", dto.getPriorityName()));
				}
				//来源
				if (dto.getImodeName() != null) {
					dto.setImodeNo(getDicItemNo("imode", dto.getImodeName()));
				}
				// 请求分类
				if (dto.getRequestCategoryName() != null) {
					try {
						EventCategory requestCategory = eventCategoryDAO.findUniqueBy("categoryRoot", MODULECATEGORY);
						List<EventCategory> rcs = requestCategory.getParentChildren();
						for (EventCategory r : rcs) {
							if (dto.getRequestCategoryName().equals(r.getEventName())) {
								dto.setRequestCategoryNo(r.getEventId());
								break;
							}
						}
					} catch (Exception e) {
						LOGGER.error("MQ_CREATE_REQUEST_REQUESTCATEGORY_ERROR", e);
					}
				}
				if (dto.getEdesc() == null || dto.getEdesc().length() < 1) {
					dto.setEdesc(dto.getEtitle());
				}
				dto.setCreator(temp.getLoginName());
				dto.setTechnicianName(temp.getLoginName());
				saveRequest(dto);
			}
		}
		if(bl){
			LOGGER.error("MQ_CREATE_REQUEST_ACCOUNT_ERROR");
		}
	}
	/**
	 * 根据根据分组和名称搜索第一个Item的编号；
	 * @param groupCode
	 * @param val
	 * @return
	 */
	public Long getDicItemNo(String groupCode,String val){
		Long no = null;
		try {
			if (groupCode != null || val != null) {
				List<DataDictionaryItems> lis = dataDictionaryItemsDAO.findItemByGroupCodeAndName(groupCode,val);
				if (lis != null && lis.size() > 0 ) {
					no = lis.get(0).getDcode();
				}
			}
		} catch (Exception e) {
			LOGGER.error(e);
		}
		return no;
	}
	
	/**
	 * 重建请求的索引
	 */
	public void reindexRequest(){
		//fullTextSearchService.index(Request.class);
    }
	
	/**
	 * 查询关联表单的请求数量
	 * @param formId
	 * @return
	 */
	public Integer findRquestNumByFormId(Long[] formIds){
		Integer num =requestDAO.findRquestNumByFormId(formIds);
		return num;
	}

	/**
	 * 查看流程任务指派人和组
	 */
	public ProcessAssignDTO findProcessAssignDTO(ProcessHandleDTO phDTO){
		Request request = requestDAO.findById(phDTO.getEno());
		Long eventId = null;
		if( request.getRequestCategory()!=null){
			eventId = request.getRequestCategory().getEventId();
		}
		String tgId = "";
		if(request.getAssigneeGroup()!=null){
			tgId = request.getAssigneeGroup().getOrgNo().toString();
		}
		final String belongsGroupIds = tgId;
		final Long categoryId = eventId;
		class AssignByBusy implements ICustomAssign{
			public Object execute(){
				return automaticallyAssignedByBusy(categoryId,belongsGroupIds,null);
			}
		}
		RequestDTO requestDTO = new RequestDTO();
		entity2dto(request, requestDTO);
		
		if(phDTO.getIsOpenProcess() && !StringUtils.hasText(phDTO.getPid())){
			String pid = bpi.startFlowInstance(ModuleUtils.ITSM_REQUEST,requestDTO.getProcessKey(),requestDTO);
			phDTO.setPid(pid);
		}
		ProcessAssignDTO processAssignDTO = bpi.findProcessAssignDTO(phDTO, requestDTO, new AssignByBusy());
		//请求审批节点指派处理
		if(requestDTO.getApprovalNo()!=null && requestDTO.getApprovalNo()!=0){
			User user = userDAO.findById(requestDTO.getApprovalNo());
			if(user!=null){
				processAssignDTO.setAssigneeName(user.getFullName());
				processAssignDTO.setAssigneeId(user.getUserId());
			}else{
				processAssignDTO.setAssigneeName(null);
				processAssignDTO.setAssigneeId(null);
			}
			processAssignDTO.setGroupId(null);
			processAssignDTO.setGroupName(null);
		}
		return processAssignDTO;
	}
	/**
	 * 统计请求分类报表
	 * @return
	 */
	public List requestCatagoryReport(){
		List rlist=requestDAO.requestCatagoryReport();
		return rlist;
	}

	/**
	 * 统计请求状态报表
	 * @return
	 */
	public List requestStatusReport(){
		List rlist=requestDAO.requestStatusReport();
		return rlist;
	}
	/**
	 * 统计SLA响应率报表
	 * @return
	 */
	public List requestSLAStatusReport(){
		List rlist=requestDAO.requestSLAStatusReport();
		return rlist;
	}
	/**
	 * 统计SLA完成率报表
	 * @return
	 */
	public List requestSLACompleteReport(){
		List rlist=requestDAO.requestSLACompleteReport();
		return rlist;
	}
	/**
	 * 技术员工作量统计
	 * @return
	 */
	public List engineerWorkloadReport(){
		List rlist=requestDAO.engineerWorkloadReport();
		return rlist;
	}
	/**
	 * 技术员忙碌程度统计
	 * @return
	 */
	public List workloadStatusStatistics(){
		List rlist=requestDAO.workloadStatusStatistics();
		return rlist;	
	}
	/**
	 * 技术员处理请求耗时
	 * @return
	 */
	public List tctakeTimeperRequest(){
		List rlist=requestDAO.tctakeTimeperRequest();
		return rlist;
	}
	/**
	 * 技术员工时统计报表
	 * @return
	 */
	public List technicianCostTime(){
		List rlist=requestDAO.technicianCostTime();
		return rlist;
	}
}